diff --git a/agent/agent-profiler/agent-alerting-api/build.gradle.kts b/agent/agent-profiler/agent-alerting-api/build.gradle.kts index abcc1ed658b..0a7244c263c 100644 --- a/agent/agent-profiler/agent-alerting-api/build.gradle.kts +++ b/agent/agent-profiler/agent-alerting-api/build.gradle.kts @@ -8,8 +8,7 @@ if (project.properties.containsKey("publish-diagnostics")) { } dependencies { - compileOnly("com.fasterxml.jackson.core:jackson-annotations") - compileOnly("com.fasterxml.jackson.core:jackson-databind") + compileOnly("com.azure:azure-json") compileOnly("com.google.auto.value:auto-value-annotations") annotationProcessor("com.google.auto.value:auto-value") } diff --git a/agent/agent-profiler/agent-alerting-api/src/main/java/com/microsoft/applicationinsights/alerting/aiconfig/AlertingConfig.java b/agent/agent-profiler/agent-alerting-api/src/main/java/com/microsoft/applicationinsights/alerting/aiconfig/AlertingConfig.java index c57c1f56991..4c627fc0e16 100644 --- a/agent/agent-profiler/agent-alerting-api/src/main/java/com/microsoft/applicationinsights/alerting/aiconfig/AlertingConfig.java +++ b/agent/agent-profiler/agent-alerting-api/src/main/java/com/microsoft/applicationinsights/alerting/aiconfig/AlertingConfig.java @@ -3,75 +3,208 @@ package com.microsoft.applicationinsights.alerting.aiconfig; -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; +import com.azure.json.JsonReader; +import com.azure.json.JsonSerializable; +import com.azure.json.JsonToken; +import com.azure.json.JsonWriter; +import java.io.IOException; public class AlertingConfig { public enum RequestFilterType { - @JsonProperty("name-regex") NAME_REGEX } - public static class RequestFilter { - public final RequestFilterType type; - public final String value; + public static class RequestFilter implements JsonSerializable { + public RequestFilterType type; + public String value; - @JsonCreator - public RequestFilter( - @JsonProperty("type") RequestFilterType type, @JsonProperty("value") String value) { + public RequestFilterType getType() { + return type; + } + + public RequestFilter setType(RequestFilterType type) { this.type = type; + return this; + } + + public String getValue() { + return value; + } + + public RequestFilter setValue(String value) { this.value = value; + return this; + } + + @Override + public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { + jsonWriter.writeStartObject(); + if (type != null) { + jsonWriter.writeStringField("type", type.name()); + } + jsonWriter.writeStringField("value", value); + jsonWriter.writeEndObject(); + return jsonWriter; + } + + public static RequestFilter fromJson(JsonReader jsonReader) throws IOException { + return jsonReader.readObject( + reader -> { + RequestFilter deserializedRequestFilter = new RequestFilter(); + while (reader.nextToken() != JsonToken.END_OBJECT) { + reader.nextToken(); + String fieldName = reader.getFieldName(); + if ("type".equals(fieldName)) { + deserializedRequestFilter.setType(RequestFilterType.valueOf(reader.getString())); + } else if ("value".equals(fieldName)) { + deserializedRequestFilter.setValue(reader.getString()); + } else { + reader.skipChildren(); + } + } + return deserializedRequestFilter; + }); } } - public static class RequestAggregationConfig { + public static class RequestAggregationConfig + implements JsonSerializable { // Threshold in ms over which a span will consider to be a breach // Used by the breach ratio aggregation - public final int thresholdMillis; + public int thresholdMillis; // Minimum number of samples that must have been collected in order for the aggregation to // produce data. Avoids volatile aggregation output on small sample sizes. - public final int minimumSamples; + public int minimumSamples; + + public int getThresholdMillis() { + return thresholdMillis; + } - @JsonCreator - public RequestAggregationConfig( - @JsonProperty("thresholdMillis") int thresholdMillis, - @JsonProperty("minimumSamples") int minimumSamples) { + public RequestAggregationConfig setThresholdMillis(int thresholdMillis) { this.thresholdMillis = thresholdMillis; + return this; + } + + public int getMinimumSamples() { + return minimumSamples; + } + + public RequestAggregationConfig setMinimumSamples(int minimumSamples) { this.minimumSamples = minimumSamples; + return this; + } + + @Override + public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { + jsonWriter.writeStartObject(); + jsonWriter.writeIntField("thresholdMillis", thresholdMillis); + jsonWriter.writeIntField("minimumSamples", minimumSamples); + jsonWriter.writeEndObject(); + return jsonWriter; + } + + public static RequestAggregationConfig fromJson(JsonReader jsonReader) throws IOException { + return jsonReader.readObject( + reader -> { + RequestAggregationConfig deserializedRequestAggregationConfig = + new RequestAggregationConfig(); + while (reader.nextToken() != JsonToken.END_OBJECT) { + reader.nextToken(); + String fieldName = reader.getFieldName(); + if ("thresholdMillis".equals(fieldName)) { + deserializedRequestAggregationConfig.setThresholdMillis(jsonReader.getInt()); + } else if ("minimumSamples".equals(fieldName)) { + deserializedRequestAggregationConfig.setMinimumSamples(jsonReader.getInt()); + } else { + reader.skipChildren(); + } + } + return deserializedRequestAggregationConfig; + }); } } public enum RequestAggregationType { - @JsonProperty("breach-ratio") BREACH_RATIO } - public static class RequestAggregation { - public final RequestAggregationType type; - public final long windowSizeMillis; // in ms - public final RequestAggregationConfig configuration; + public static class RequestAggregation implements JsonSerializable { + public RequestAggregationType type; + public long windowSizeMillis; // in ms + public RequestAggregationConfig configuration; + + public RequestAggregationType getType() { + return type; + } - @JsonCreator - public RequestAggregation( - @JsonProperty("type") RequestAggregationType type, - @JsonProperty("windowSizeMillis") long windowSizeMillis, - @JsonProperty("configuration") RequestAggregationConfig configuration) { + public RequestAggregation setType(RequestAggregationType type) { this.type = type; + return this; + } + + public long getWindowSizeMillis() { + return windowSizeMillis; + } + + public RequestAggregation setWindowSizeMillis(long windowSizeMillis) { this.windowSizeMillis = windowSizeMillis; + return this; + } + + public RequestAggregationConfig getConfiguration() { + return configuration; + } + + public RequestAggregation setConfiguration(RequestAggregationConfig configuration) { this.configuration = configuration; + return this; + } + + @Override + public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { + jsonWriter.writeStartObject(); + if (type != null) { + jsonWriter.writeStringField("type", type.name()); + } + jsonWriter.writeLongField("windowSizeMillis", windowSizeMillis); + jsonWriter.writeJsonField("configuration", configuration); + jsonWriter.writeEndObject(); + return jsonWriter; + } + + public static RequestAggregation fromJson(JsonReader jsonReader) throws IOException { + return jsonReader.readObject( + reader -> { + RequestAggregation deserializedRequestAggregation = new RequestAggregation(); + while (reader.nextToken() != JsonToken.END_OBJECT) { + reader.nextToken(); + String fieldName = reader.getFieldName(); + if ("type".equals(fieldName)) { + deserializedRequestAggregation.setType( + RequestAggregationType.valueOf(reader.getString())); + } else if ("windowSizeMillis".equals(fieldName)) { + deserializedRequestAggregation.setWindowSizeMillis(jsonReader.getLong()); + } else if ("configuration".equals(fieldName)) { + deserializedRequestAggregation.setConfiguration( + RequestAggregationConfig.fromJson(jsonReader)); + } else { + reader.skipChildren(); + } + } + return deserializedRequestAggregation; + }); } } public enum RequestTriggerThresholdType { - @JsonProperty("greater-than") GREATER_THAN } - public static class RequestTriggerThreshold { - public final RequestTriggerThresholdType type; + public static class RequestTriggerThreshold implements JsonSerializable { + public RequestTriggerThresholdType type; // Threshold value applied to the output of the aggregation // i.e : @@ -80,65 +213,236 @@ public static class RequestTriggerThreshold { // - For a rolling average aggregation 0.75 will mean this will trigger if the average request // processing time // breaches 0.75ms - public final float value; + public float value; + + public RequestTriggerThresholdType getType() { + return type; + } - @JsonCreator - public RequestTriggerThreshold( - @JsonProperty("type") RequestTriggerThresholdType type, - @JsonProperty("value") float value) { + public RequestTriggerThreshold setType(RequestTriggerThresholdType type) { this.type = type; + return this; + } + + public float getValue() { + return value; + } + + public RequestTriggerThreshold setValue(float value) { this.value = value; + return this; + } + + @Override + public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { + jsonWriter.writeStartObject(); + if (type != null) { + jsonWriter.writeStringField("type", type.name()); + } + jsonWriter.writeFloatField("value", value); + jsonWriter.writeEndObject(); + return jsonWriter; + } + + public static RequestTriggerThreshold fromJson(JsonReader jsonReader) throws IOException { + return jsonReader.readObject( + reader -> { + RequestTriggerThreshold deserializedRequestTriggerThreshold = + new RequestTriggerThreshold(); + while (reader.nextToken() != JsonToken.END_OBJECT) { + reader.nextToken(); + String fieldName = reader.getFieldName(); + if ("type".equals(fieldName)) { + deserializedRequestTriggerThreshold.setType( + RequestTriggerThresholdType.valueOf(reader.getString())); + } else if ("value".equals(fieldName)) { + deserializedRequestTriggerThreshold.setValue(reader.getFloat()); + } else { + reader.skipChildren(); + } + } + return deserializedRequestTriggerThreshold; + }); } } public enum RequestTriggerThrottlingType { - @JsonProperty("fixed-duration-cooldown") FIXED_DURATION_COOLDOWN } - public static class RequestTriggerThrottling { - public final RequestTriggerThrottlingType type; - public final long value; // in seconds + public static class RequestTriggerThrottling + implements JsonSerializable { + public RequestTriggerThrottlingType type; + public long value; // in seconds + + public RequestTriggerThrottlingType getType() { + return type; + } - @JsonCreator - public RequestTriggerThrottling( - @JsonProperty("type") RequestTriggerThrottlingType type, - @JsonProperty("value") long value) { + public RequestTriggerThrottling setType(RequestTriggerThrottlingType type) { this.type = type; + return this; + } + + public long getValue() { + return value; + } + + public RequestTriggerThrottling setValue(long value) { this.value = value; + return this; + } + + @Override + public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { + jsonWriter.writeStartObject(); + if (type != null) { + jsonWriter.writeStringField("type", type.name()); + } + jsonWriter.writeLongField("value", value); + jsonWriter.writeEndObject(); + return jsonWriter; + } + + public static RequestTriggerThrottling fromJson(JsonReader jsonReader) throws IOException { + return jsonReader.readObject( + reader -> { + RequestTriggerThrottling deserializedRequestTriggerThrottling = + new RequestTriggerThrottling(); + while (reader.nextToken() != JsonToken.END_OBJECT) { + reader.nextToken(); + String fieldName = reader.getFieldName(); + if ("type".equals(fieldName)) { + deserializedRequestTriggerThrottling.setType( + RequestTriggerThrottlingType.valueOf(reader.getString())); + } else if ("value".equals(fieldName)) { + deserializedRequestTriggerThrottling.setValue(reader.getLong()); + } else { + reader.skipChildren(); + } + } + return deserializedRequestTriggerThrottling; + }); } } public enum RequestTriggerType { - @JsonProperty("latency") LATENCY } - public static class RequestTrigger { - public final String name; - public final RequestTriggerType type; - public final RequestFilter filter; - public final RequestAggregation aggregation; - public final RequestTriggerThreshold threshold; - public final RequestTriggerThrottling throttling; - public final long profileDuration; - - @JsonCreator - public RequestTrigger( - @JsonProperty("name") String name, - @JsonProperty("type") RequestTriggerType type, - @JsonProperty("filter") RequestFilter filter, - @JsonProperty("aggregation") RequestAggregation aggregation, - @JsonProperty("threshold") RequestTriggerThreshold threshold, - @JsonProperty("throttling") RequestTriggerThrottling throttling, - @JsonProperty("profileDuration") long profileDuration) { + public static class RequestTrigger implements JsonSerializable { + public String name; + public RequestTriggerType type; + public RequestFilter filter; + public RequestAggregation aggregation; + public RequestTriggerThreshold threshold; + public RequestTriggerThrottling throttling; + public long profileDuration; + + public String getName() { + return name; + } + + public RequestTrigger setName(String name) { this.name = name; + return this; + } + + public RequestTriggerType getType() { + return type; + } + + public RequestTrigger setType(RequestTriggerType type) { this.type = type; + return this; + } + + public RequestFilter getFilter() { + return filter; + } + + public RequestTrigger setFilter(RequestFilter filter) { this.filter = filter; + return this; + } + + public RequestAggregation getAggregation() { + return aggregation; + } + + public RequestTrigger setAggregation(RequestAggregation aggregation) { this.aggregation = aggregation; + return this; + } + + public RequestTriggerThreshold getThreshold() { + return threshold; + } + + public RequestTrigger setThreshold(RequestTriggerThreshold threshold) { this.threshold = threshold; + return this; + } + + public RequestTriggerThrottling getThrottling() { + return throttling; + } + + public RequestTrigger setThrottling(RequestTriggerThrottling throttling) { this.throttling = throttling; + return this; + } + + public long getProfileDuration() { + return profileDuration; + } + + public RequestTrigger setProfileDuration(long profileDuration) { this.profileDuration = profileDuration; + return this; + } + + @Override + public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { + jsonWriter.writeStartObject(); + jsonWriter.writeStringField("name", name); + jsonWriter.writeStringField("type", type.name()); + jsonWriter.writeJsonField("filter", filter); + jsonWriter.writeJsonField("aggregation", aggregation); + jsonWriter.writeJsonField("threshold", threshold); + jsonWriter.writeJsonField("throttling", throttling); + jsonWriter.writeLongField("profileDuration", profileDuration); + jsonWriter.writeEndObject(); + return jsonWriter; + } + + public static RequestTrigger fromJson(JsonReader jsonReader) throws IOException { + return jsonReader.readObject( + reader -> { + RequestTrigger deserializedRequestTrigger = new RequestTrigger(); + while (reader.nextToken() != JsonToken.END_OBJECT) { + reader.nextToken(); + String fieldName = reader.getFieldName(); + if ("name".equals(fieldName)) { + deserializedRequestTrigger.setName(reader.getString()); + } else if ("type".equals(fieldName)) { + deserializedRequestTrigger.setType(RequestTriggerType.valueOf(reader.getString())); + } else if ("filter".equals(fieldName)) { + deserializedRequestTrigger.setFilter(RequestFilter.fromJson(reader)); + } else if ("aggregation".equals(fieldName)) { + deserializedRequestTrigger.setAggregation(RequestAggregation.fromJson(reader)); + } else if ("threshold".equals(fieldName)) { + deserializedRequestTrigger.setThreshold(RequestTriggerThreshold.fromJson(reader)); + } else if ("throttling".equals(fieldName)) { + deserializedRequestTrigger.setThrottling(RequestTriggerThrottling.fromJson(reader)); + } else if ("profileDuration".equals(fieldName)) { + deserializedRequestTrigger.setProfileDuration(reader.getLong()); + } else { + reader.skipChildren(); + } + } + return deserializedRequestTrigger; + }); } } diff --git a/agent/agent-profiler/agent-alerting-api/src/main/java/com/microsoft/applicationinsights/alerting/alert/AlertBreach.java b/agent/agent-profiler/agent-alerting-api/src/main/java/com/microsoft/applicationinsights/alerting/alert/AlertBreach.java index 502ba7b282e..f6e07b844b1 100644 --- a/agent/agent-profiler/agent-alerting-api/src/main/java/com/microsoft/applicationinsights/alerting/alert/AlertBreach.java +++ b/agent/agent-profiler/agent-alerting-api/src/main/java/com/microsoft/applicationinsights/alerting/alert/AlertBreach.java @@ -3,45 +3,71 @@ package com.microsoft.applicationinsights.alerting.alert; -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.azure.json.JsonSerializable; +import com.azure.json.JsonWriter; import com.google.auto.value.AutoValue; import com.microsoft.applicationinsights.alerting.config.AlertConfiguration; import com.microsoft.applicationinsights.alerting.config.AlertMetricType; +import java.io.IOException; import java.util.UUID; /** Represents a breach of an alert threshold. */ @AutoValue -@JsonSerialize(as = AlertBreach.class) -@JsonDeserialize(builder = AlertBreach.Builder.class) -@JsonIgnoreProperties(ignoreUnknown = true) -public abstract class AlertBreach { +public abstract class AlertBreach implements JsonSerializable { + + private AlertMetricType type; + private double alertValue; + private AlertConfiguration alertConfiguration; + private double cpuMetric; + private double memoryUsage; + private String profileId = UUID.randomUUID().toString(); - @JsonProperty("type") public abstract AlertMetricType getType(); + public AlertBreach setType(AlertMetricType type) { + this.type = type; + return this; + } + // Value of the telemetry at the time of the breach - @JsonProperty("alertValue") public abstract double getAlertValue(); - @JsonProperty("alertConfiguration") + public AlertBreach setAlertValue(double alertValue) { + this.alertValue = alertValue; + return this; + } + public abstract AlertConfiguration getAlertConfiguration(); + public AlertBreach setAlertConfiguration(AlertConfiguration alertConfiguration) { + this.alertConfiguration = alertConfiguration; + return this; + } + // CPU usage at the time of the breach - @JsonProperty(value = "cpuMetric") public abstract double getCpuMetric(); + public AlertBreach setCpuMetric(double cpuMetric) { + this.cpuMetric = cpuMetric; + return this; + } + // MEMORY usage at the time of the breach - @JsonProperty(value = "memoryUsage") public abstract double getMemoryUsage(); + public AlertBreach setMemoryUsage(double memoryUsage) { + this.memoryUsage = memoryUsage; + return this; + } + // Unique ID for profile/breach - @JsonProperty("profileId") public abstract String getProfileId(); + public AlertBreach setProfileId(String profileId) { + this.profileId = profileId; + return this; + } + public abstract Builder toBuilder(); public static AlertBreach.Builder builder() { @@ -51,33 +77,57 @@ public static AlertBreach.Builder builder() { .setProfileId(UUID.randomUUID().toString()); } - @AutoValue.Builder - @JsonIgnoreProperties(ignoreUnknown = true) - public abstract static class Builder { - - @JsonCreator - public static Builder builder() { - return AlertBreach.builder(); + @Override + public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { + jsonWriter.writeStartObject(); + if (type != null) { + jsonWriter.writeStringField("type", type.name()); } + jsonWriter.writeDoubleField("alertValue", alertValue); + jsonWriter.writeJsonField("alertConfiguration", alertConfiguration); + jsonWriter.writeDoubleField("cpuMetric", cpuMetric); + jsonWriter.writeDoubleField("memoryUsage", memoryUsage); + jsonWriter.writeStringField("profileId", profileId); + jsonWriter.writeEndObject(); + return jsonWriter; + } + + @AutoValue.Builder + public abstract static class Builder implements JsonSerializable { + private AlertMetricType type; + private double alertValue; + private AlertConfiguration alertConfiguration; + private double cpuMetric; + private double memoryUsage; + private final String profileId = UUID.randomUUID().toString(); - @JsonProperty("type") public abstract Builder setType(AlertMetricType type); - @JsonProperty("alertValue") public abstract Builder setAlertValue(double alertValue); - @JsonProperty("alertConfiguration") public abstract Builder setAlertConfiguration(AlertConfiguration alertConfiguration); - @JsonProperty(value = "cpuMetric") public abstract Builder setCpuMetric(double cpuMetric); - @JsonProperty(value = "memoryUsage") public abstract Builder setMemoryUsage(double memoryUsage); - @JsonProperty("profileId") public abstract Builder setProfileId(String profileId); public abstract AlertBreach build(); + + @Override + public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { + jsonWriter.writeStartObject(); + if (type != null) { + jsonWriter.writeStringField("type", type.name()); + } + jsonWriter.writeDoubleField("alertValue", alertValue); + jsonWriter.writeJsonField("alertConfiguration", alertConfiguration); + jsonWriter.writeDoubleField("cpuMetric", cpuMetric); + jsonWriter.writeDoubleField("memoryUsage", memoryUsage); + jsonWriter.writeStringField("profileId", profileId); + jsonWriter.writeEndObject(); + return jsonWriter; + } } } diff --git a/agent/agent-profiler/agent-alerting-api/src/main/java/com/microsoft/applicationinsights/alerting/config/AlertConfiguration.java b/agent/agent-profiler/agent-alerting-api/src/main/java/com/microsoft/applicationinsights/alerting/config/AlertConfiguration.java index d1bad74aaa5..a632462fa03 100644 --- a/agent/agent-profiler/agent-alerting-api/src/main/java/com/microsoft/applicationinsights/alerting/config/AlertConfiguration.java +++ b/agent/agent-profiler/agent-alerting-api/src/main/java/com/microsoft/applicationinsights/alerting/config/AlertConfiguration.java @@ -3,39 +3,82 @@ package com.microsoft.applicationinsights.alerting.config; -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.azure.json.JsonSerializable; +import com.azure.json.JsonWriter; import com.google.auto.value.AutoValue; import com.microsoft.applicationinsights.alerting.aiconfig.AlertingConfig; +import java.io.IOException; import javax.annotation.Nullable; /** Alert configuration for a given telemetry type. */ @AutoValue -@JsonSerialize(as = AlertConfiguration.class) -@JsonDeserialize(builder = AlertConfiguration.Builder.class) -public abstract class AlertConfiguration { +public abstract class AlertConfiguration implements JsonSerializable { + + protected AlertMetricType type; + protected boolean enabled; + protected float threshold; + protected int profileDurationSeconds; + protected int cooldownSeconds; + protected AlertingConfig.RequestTrigger requestTrigger; - @JsonProperty("type") public abstract AlertMetricType getType(); - @JsonProperty("enabled") + public AlertConfiguration setType(AlertMetricType type) { + this.type = type; + return this; + } + public abstract boolean isEnabled(); - @JsonProperty("threshold") + public AlertConfiguration setEnabled(boolean enabled) { + this.enabled = enabled; + return this; + } + public abstract float getThreshold(); - @JsonProperty("profileDuration") + public AlertConfiguration setThreshold(float threshold) { + this.threshold = threshold; + return this; + } + public abstract int getProfileDurationSeconds(); - @JsonProperty("cooldown") + public AlertConfiguration setProfileDurationSeconds(int profileDurationSeconds) { + this.profileDurationSeconds = profileDurationSeconds; + return this; + } + public abstract int getCooldownSeconds(); + public AlertConfiguration setCooldownSeconds(int cooldownSeconds) { + this.cooldownSeconds = cooldownSeconds; + return this; + } + @Nullable - @JsonProperty("requestTrigger") public abstract AlertingConfig.RequestTrigger getRequestTrigger(); + public AlertConfiguration setRequestTrigger(AlertingConfig.RequestTrigger requestTrigger) { + this.requestTrigger = requestTrigger; + return this; + } + + @Override + public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { + jsonWriter.writeStartObject(); + if (type != null) { + jsonWriter.writeStringField("type", type.name()); + } + jsonWriter.writeBooleanField("enabled", enabled); + jsonWriter.writeFloatField("threshold", threshold); + jsonWriter.writeIntField("profileDurationSeconds", profileDurationSeconds); + jsonWriter.writeIntField("cooldownSeconds", cooldownSeconds); + jsonWriter.writeJsonField("requestTrigger", requestTrigger); + jsonWriter.writeEndObject(); + return jsonWriter; + } + public static Builder builder() { // TODO (trask) which of these is really required? return new AutoValue_AlertConfiguration.Builder() @@ -46,31 +89,42 @@ public static Builder builder() { } @AutoValue.Builder - public abstract static class Builder { - @JsonCreator - public static Builder builder() { - return AlertConfiguration.builder(); - } + public abstract static class Builder implements JsonSerializable { + private AlertMetricType type; + private boolean enabled; + private float threshold; + private int profileDurationSeconds; + private int cooldownSeconds; + private AlertingConfig.RequestTrigger requestTrigger; - @JsonProperty("enabled") public abstract Builder setEnabled(boolean enabled); - @JsonProperty("threshold") public abstract Builder setThreshold(float threshold); - @JsonProperty("profileDuration") public abstract Builder setProfileDurationSeconds(int profileDurationSeconds); - @JsonProperty("cooldown") public abstract Builder setCooldownSeconds(int cooldownSeconds); - @JsonProperty("type") public abstract Builder setType(AlertMetricType type); - @JsonProperty("requestTrigger") public abstract Builder setRequestTrigger( @Nullable AlertingConfig.RequestTrigger requestTrigger); public abstract AlertConfiguration build(); + + @Override + public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { + jsonWriter.writeStartObject(); + if (type != null) { + jsonWriter.writeStringField("type", type.name()); + } + jsonWriter.writeBooleanField("enabled", enabled); + jsonWriter.writeFloatField("threshold", threshold); + jsonWriter.writeIntField("profileDurationSeconds", profileDurationSeconds); + jsonWriter.writeIntField("cooldownSeconds", cooldownSeconds); + jsonWriter.writeJsonField("requestTrigger", requestTrigger); + jsonWriter.writeEndObject(); + return jsonWriter; + } } } diff --git a/agent/agent-profiler/agent-alerting-api/src/main/java/com/microsoft/applicationinsights/alerting/config/AlertMetricType.java b/agent/agent-profiler/agent-alerting-api/src/main/java/com/microsoft/applicationinsights/alerting/config/AlertMetricType.java index 871255cb444..104934afa8a 100644 --- a/agent/agent-profiler/agent-alerting-api/src/main/java/com/microsoft/applicationinsights/alerting/config/AlertMetricType.java +++ b/agent/agent-profiler/agent-alerting-api/src/main/java/com/microsoft/applicationinsights/alerting/config/AlertMetricType.java @@ -8,5 +8,5 @@ public enum AlertMetricType { MEMORY, PERIODIC, MANUAL, - REQUEST + REQUEST; } diff --git a/agent/agent-profiler/agent-alerting/build.gradle.kts b/agent/agent-profiler/agent-alerting/build.gradle.kts index 5bf7fcc0cf2..1f69e7a786a 100644 --- a/agent/agent-profiler/agent-alerting/build.gradle.kts +++ b/agent/agent-profiler/agent-alerting/build.gradle.kts @@ -8,6 +8,7 @@ dependencies { implementation(project(":agent:agent-profiler:agent-alerting-api")) implementation("org.slf4j:slf4j-api") + implementation("com.azure:azure-json") testImplementation("org.junit.jupiter:junit-jupiter") testImplementation("org.assertj:assertj-core") diff --git a/agent/agent-profiler/agent-alerting/gradle.lockfile b/agent/agent-profiler/agent-alerting/gradle.lockfile index e488a4d7ac2..427a33ff2a1 100644 --- a/agent/agent-profiler/agent-alerting/gradle.lockfile +++ b/agent/agent-profiler/agent-alerting/gradle.lockfile @@ -1,6 +1,7 @@ # This is a Gradle generated file for dependency locking. # Manual edits can break the build and are not advised. # This file is expected to be part of source control. +com.azure:azure-json:1.3.0=runtimeClasspath com.azure:azure-sdk-bom:1.2.29=runtimeClasspath com.fasterxml.jackson:jackson-bom:2.18.1=runtimeClasspath io.netty:netty-bom:4.1.114.Final=runtimeClasspath diff --git a/agent/agent-profiler/agent-diagnostics-jfr/build.gradle.kts b/agent/agent-profiler/agent-diagnostics-jfr/build.gradle.kts index 12b595e444f..3ad0bc9a6e5 100644 --- a/agent/agent-profiler/agent-diagnostics-jfr/build.gradle.kts +++ b/agent/agent-profiler/agent-diagnostics-jfr/build.gradle.kts @@ -9,9 +9,7 @@ if (project.properties.containsKey("publish-diagnostics")) { dependencies { compileOnly("org.gradle.jfr.polyfill:jfr-polyfill:1.0.2") - - compileOnly("com.fasterxml.jackson.core:jackson-annotations") - + compileOnly("com.azure:azure-json") compileOnly("com.google.auto.service:auto-service") annotationProcessor("com.google.auto.service:auto-service") } diff --git a/agent/agent-profiler/agent-diagnostics-jfr/src/main/java/com/microsoft/applicationinsights/diagnostics/jfr/AlertBreachJfrEvent.java b/agent/agent-profiler/agent-diagnostics-jfr/src/main/java/com/microsoft/applicationinsights/diagnostics/jfr/AlertBreachJfrEvent.java index 73c483e08f4..1fada49e8d6 100644 --- a/agent/agent-profiler/agent-diagnostics-jfr/src/main/java/com/microsoft/applicationinsights/diagnostics/jfr/AlertBreachJfrEvent.java +++ b/agent/agent-profiler/agent-diagnostics-jfr/src/main/java/com/microsoft/applicationinsights/diagnostics/jfr/AlertBreachJfrEvent.java @@ -3,6 +3,11 @@ package com.microsoft.applicationinsights.diagnostics.jfr; +import com.azure.json.JsonReader; +import com.azure.json.JsonSerializable; +import com.azure.json.JsonToken; +import com.azure.json.JsonWriter; +import java.io.IOException; import jdk.jfr.Category; import jdk.jfr.Description; import jdk.jfr.Event; @@ -16,17 +21,46 @@ @Category("Diagnostic") @Description("AlertBreach") @StackTrace(false) -public class AlertBreachJfrEvent extends Event { +public class AlertBreachJfrEvent extends Event implements JsonSerializable { public static final String NAME = "com.microsoft.applicationinsights.diagnostics.jfr.AlertBreach"; - private final String alertBreach; + private String alertBreach; - public AlertBreachJfrEvent(String alertBreach) { - this.alertBreach = alertBreach; - } + public AlertBreachJfrEvent() {} public String getAlertBreach() { return alertBreach; } + + public AlertBreachJfrEvent setAlertBreach(String alertBreach) { + this.alertBreach = alertBreach; + return this; + } + + /** Serialize a AlertBreachJfrEvent to a JSON writer */ + @Override + public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { + jsonWriter.writeStartObject(); + jsonWriter.writeStringField("alertBreach", alertBreach); + jsonWriter.writeEndObject(); + return jsonWriter; + } + + /** Deserialize a AlertBreachJfrEvent from a JSON reader */ + public static AlertBreachJfrEvent fromJson(JsonReader jsonReader) throws IOException { + return jsonReader.readObject( + reader -> { + AlertBreachJfrEvent event = new AlertBreachJfrEvent(); + while (reader.nextToken() != JsonToken.END_OBJECT) { + String fieldName = reader.getFieldName(); + reader.nextToken(); + + if ("alertBreach".equals(fieldName)) { + event.setAlertBreach(reader.getString()); + } + } + return event; + }); + } } diff --git a/agent/agent-profiler/agent-diagnostics-jfr/src/main/java/com/microsoft/applicationinsights/diagnostics/jfr/CGroupData.java b/agent/agent-profiler/agent-diagnostics-jfr/src/main/java/com/microsoft/applicationinsights/diagnostics/jfr/CGroupData.java index aed9ff500fe..884a3449b84 100644 --- a/agent/agent-profiler/agent-diagnostics-jfr/src/main/java/com/microsoft/applicationinsights/diagnostics/jfr/CGroupData.java +++ b/agent/agent-profiler/agent-diagnostics-jfr/src/main/java/com/microsoft/applicationinsights/diagnostics/jfr/CGroupData.java @@ -3,8 +3,11 @@ package com.microsoft.applicationinsights.diagnostics.jfr; -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; +import com.azure.json.JsonReader; +import com.azure.json.JsonSerializable; +import com.azure.json.JsonToken; +import com.azure.json.JsonWriter; +import java.io.IOException; import jdk.jfr.Category; import jdk.jfr.Description; import jdk.jfr.Event; @@ -20,63 +23,107 @@ @Description("CGroupData") @StackTrace(false) @Period("beginChunk") -public class CGroupData extends Event { +public class CGroupData extends Event implements JsonSerializable { public static final String NAME = "com.microsoft.applicationinsights.diagnostics.jfr.CGroupData"; - public static final int CGROUP_DATA_ABSENT = -2; + public static final int CGROUP_DATA_ABSENT = -2; // No CGroup data was found for this value // Limit of the kernel memory - private final long kmemLimit; // /sys/fs/cgroup/memory/memory.kmem.limit_in_bytes + private long kmemLimit; // /sys/fs/cgroup/memory/memory.kmem.limit_in_bytes // Limit of the containers memory - private final long memoryLimit; // /sys/fs/cgroup/memory/memory.limit_in_bytes + private long memoryLimit; // /sys/fs/cgroup/memory/memory.limit_in_bytes // Soft memory limit (enforced over the long term) - private final long memorySoftLimit; // /sys/fs/cgroup/memory/memory.soft_limit_in_bytes + private long memorySoftLimit; // /sys/fs/cgroup/memory/memory.soft_limit_in_bytes // CPU usage limit - private final long cpuLimit; // /sys/fs/cgroup/cpu,cpuacct/cpu.cfs_quota_us + private long cpuLimit; // /sys/fs/cgroup/cpu,cpuacct/cpu.cfs_quota_us // CPU usage period - private final long cpuPeriod; // /sys/fs/cgroup/cpu,cpuacct/cpu.cfs_quota_us - - @JsonCreator - public CGroupData( - @JsonProperty(value = "kmemLimit") long kmemLimit, - @JsonProperty(value = "memoryLimit") long memoryLimit, - @JsonProperty(value = "memorySoftLimit") long memorySoftLimit, - @JsonProperty(value = "cpuLimit") long cpuLimit, - @JsonProperty(value = "cpuPeriod", required = false) Long cpuPeriod) { - this.kmemLimit = kmemLimit; - this.memoryLimit = memoryLimit; - this.memorySoftLimit = memorySoftLimit; - this.cpuLimit = cpuLimit; - - if (cpuPeriod == null) { - // No CGroup data was found for this value - this.cpuPeriod = CGROUP_DATA_ABSENT; - } else { - this.cpuPeriod = cpuPeriod; - } - } + private long cpuPeriod = CGROUP_DATA_ABSENT; // /sys/fs/cgroup/cpu,cpuacct/cpu.cfs_quota_us public long getKmemLimit() { return kmemLimit; } + public CGroupData setKmemLimit(long kmemLimit) { + this.kmemLimit = kmemLimit; + return this; + } + public long getMemoryLimit() { return memoryLimit; } + public CGroupData setMemoryLimit(long memoryLimit) { + this.memoryLimit = memoryLimit; + return this; + } + public long getMemorySoftLimit() { return memorySoftLimit; } + public CGroupData setMemorySoftLimit(long memorySoftLimit) { + this.memorySoftLimit = memorySoftLimit; + return this; + } + public long getCpuLimit() { return cpuLimit; } + public CGroupData setCpuLimit(long cpuLimit) { + this.cpuLimit = cpuLimit; + return this; + } + public long getCpuPeriod() { return cpuPeriod; } + + public CGroupData setCpuPeriod(long cpuPeriod) { + this.cpuPeriod = cpuPeriod; + return this; + } + + @Override + public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { + return jsonWriter + .writeStartObject() + .writeLongField("kmemLimit", kmemLimit) + .writeLongField("memoryLimit", memoryLimit) + .writeLongField("memorySoftLimit", memorySoftLimit) + .writeLongField("cpuLimit", cpuLimit) + .writeLongField("cpuPeriod", cpuPeriod) + .writeEndObject(); + } + + public static CGroupData fromJson(JsonReader jsonReader) throws IOException { + return jsonReader.readObject( + reader -> { + CGroupData deserializedValue = new CGroupData(); + + while (reader.nextToken() != JsonToken.END_OBJECT) { + String fieldName = reader.getFieldName(); + reader.nextToken(); + if ("kmemLimit".equals(fieldName)) { + deserializedValue.setKmemLimit(reader.getLong()); + } else if ("memoryLimit".equals(fieldName)) { + deserializedValue.setMemoryLimit(reader.getLong()); + } else if ("memorySoftLimit".equals(fieldName)) { + deserializedValue.setMemorySoftLimit(reader.getLong()); + } else if ("cpuLimit".equals(fieldName)) { + deserializedValue.setCpuLimit(reader.getLong()); + } else if ("cpuPeriod".equals(fieldName)) { + deserializedValue.setCpuPeriod(reader.getLong()); + } else { + reader.skipChildren(); + } + } + + return deserializedValue; + }); + } } diff --git a/agent/agent-profiler/agent-diagnostics-jfr/src/main/java/com/microsoft/applicationinsights/diagnostics/jfr/MachineStats.java b/agent/agent-profiler/agent-diagnostics-jfr/src/main/java/com/microsoft/applicationinsights/diagnostics/jfr/MachineStats.java index 3261685140a..78af8180d7e 100644 --- a/agent/agent-profiler/agent-diagnostics-jfr/src/main/java/com/microsoft/applicationinsights/diagnostics/jfr/MachineStats.java +++ b/agent/agent-profiler/agent-diagnostics-jfr/src/main/java/com/microsoft/applicationinsights/diagnostics/jfr/MachineStats.java @@ -3,6 +3,11 @@ package com.microsoft.applicationinsights.diagnostics.jfr; +import com.azure.json.JsonReader; +import com.azure.json.JsonSerializable; +import com.azure.json.JsonToken; +import com.azure.json.JsonWriter; +import java.io.IOException; import jdk.jfr.Category; import jdk.jfr.Description; import jdk.jfr.Event; @@ -18,23 +23,58 @@ @Description("MachineStats") @StackTrace(false) @Period("beginChunk") -public class MachineStats extends Event { +public class MachineStats extends Event implements JsonSerializable { public static final String NAME = "com.microsoft.applicationinsights.diagnostics.jfr.MachineStats"; - private final double contextSwitchesPerMs; + private double contextSwitchesPerMs; - private final int coreCount; - - public MachineStats(double contextSwitchesPerMs, int coreCount) { - this.contextSwitchesPerMs = contextSwitchesPerMs; - this.coreCount = coreCount; - } + private int coreCount; public double getContextSwitchesPerMs() { return contextSwitchesPerMs; } + public MachineStats setContextSwitchesPerMs(double contextSwitchesPerMs) { + this.contextSwitchesPerMs = contextSwitchesPerMs; + return this; + } + public int getCoreCount() { return coreCount; } + + public MachineStats setCoreCount(int coreCount) { + this.coreCount = coreCount; + return this; + } + + @Override + public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { + return jsonWriter + .writeStartObject() + .writeDoubleField("contextSwitchesPerMs", contextSwitchesPerMs) + .writeIntField("coreCount", coreCount) + .writeEndObject(); + } + + public static MachineStats fromJson(JsonReader jsonReader) throws IOException { + return jsonReader.readObject( + reader -> { + MachineStats deserializedValue = new MachineStats(); + + while (reader.nextToken() != JsonToken.END_OBJECT) { + String fieldName = reader.getFieldName(); + reader.nextToken(); + if ("contextSwitchesPerMs".equals(fieldName)) { + deserializedValue.setContextSwitchesPerMs(reader.getDouble()); + } else if ("coreCount".equals(fieldName)) { + deserializedValue.setCoreCount(reader.getInt()); + } else { + reader.skipChildren(); + } + } + + return deserializedValue; + }); + } } diff --git a/agent/agent-profiler/agent-diagnostics-jfr/src/main/java/com/microsoft/applicationinsights/diagnostics/jfr/Telemetry.java b/agent/agent-profiler/agent-diagnostics-jfr/src/main/java/com/microsoft/applicationinsights/diagnostics/jfr/Telemetry.java index 46c3023faa5..6164117c1b8 100644 --- a/agent/agent-profiler/agent-diagnostics-jfr/src/main/java/com/microsoft/applicationinsights/diagnostics/jfr/Telemetry.java +++ b/agent/agent-profiler/agent-diagnostics-jfr/src/main/java/com/microsoft/applicationinsights/diagnostics/jfr/Telemetry.java @@ -3,7 +3,11 @@ package com.microsoft.applicationinsights.diagnostics.jfr; -import com.fasterxml.jackson.annotation.JsonCreator; +import com.azure.json.JsonReader; +import com.azure.json.JsonSerializable; +import com.azure.json.JsonToken; +import com.azure.json.JsonWriter; +import java.io.IOException; import java.util.List; import java.util.StringJoiner; import jdk.jfr.Category; @@ -21,44 +25,76 @@ @Description("Telemetry") @StackTrace(false) @Period("100 ms") -public class Telemetry extends Event { +public class Telemetry extends Event implements JsonSerializable { public static final String NAME = "com.microsoft.applicationinsights.diagnostics.jfr.Telemetry"; - public static final int LATEST_VERSION = 3; + private static final int LATEST_VERSION = 3; - public final int version; - public final String telemetry; + private int version = 1; + private String telemetry; - @JsonCreator - public Telemetry(Integer version, String telemetry) { - if (version == null) { - this.version = 1; - } else { - this.version = version; + public int getVersion() { + return version; + } + + public Telemetry setVersion(int version) { + this.version = version; + return this; + } + + public String getTelemetry() { + return telemetry; + } + + @SuppressWarnings("unchecked") + public Telemetry setTelemetry(Object telemetry) { + if (telemetry instanceof List) { + StringJoiner joiner = new StringJoiner(","); + ((List) telemetry) + .forEach( + it -> { + if (it == null) { + joiner.add("null"); + } else { + joiner.add(Double.toString(it)); + } + }); + this.telemetry = joiner.toString(); + this.version = LATEST_VERSION; + } else if (telemetry instanceof String) { + this.telemetry = (String) telemetry; + this.version = LATEST_VERSION; } - this.telemetry = telemetry; + return this; } - public Telemetry(String telemetry) { - this.telemetry = telemetry; - this.version = LATEST_VERSION; + @Override + public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { + return jsonWriter + .writeStartObject() + .writeIntField("version", version) + .writeStringField("telemetry", telemetry) + .writeEndObject(); } - public Telemetry(List telemetry) { - StringJoiner joiner = new StringJoiner(","); - telemetry.forEach( - it -> { - if (it == null) { - joiner.add("null"); - } else { - joiner.add(Double.toString(it)); + public static Telemetry fromJson(JsonReader jsonReader) throws IOException { + return jsonReader.readObject( + reader -> { + Telemetry deserializedValue = new Telemetry(); + + while (reader.nextToken() != JsonToken.END_OBJECT) { + String fieldName = reader.getFieldName(); + reader.nextToken(); + if ("version".equals(fieldName)) { + deserializedValue.setVersion(reader.getInt()); + } else if ("telemetry".equals(fieldName)) { + deserializedValue.setTelemetry(reader.getString()); + } else { + reader.skipChildren(); + } } - }); - this.telemetry = joiner.toString(); - this.version = LATEST_VERSION; - } - public int getVersion() { - return version; + return deserializedValue; + }); } } diff --git a/agent/agent-profiler/agent-diagnostics-serialization/build.gradle.kts b/agent/agent-profiler/agent-diagnostics-serialization/build.gradle.kts deleted file mode 100644 index d092f84c86e..00000000000 --- a/agent/agent-profiler/agent-diagnostics-serialization/build.gradle.kts +++ /dev/null @@ -1,19 +0,0 @@ -plugins { - id("ai.java-conventions") -} - -// Allows publishing this library to the local host ONLY if -Ppublish-diagnostics is provided -if (project.properties.containsKey("publish-diagnostics")) { - apply(plugin = "ai.publish-conventions") -} - -dependencies { - implementation(project(":agent:agent-profiler:agent-alerting-api")) - - compileOnly("org.slf4j:slf4j-api") - compileOnly("com.fasterxml.jackson.core:jackson-annotations") - compileOnly("com.fasterxml.jackson.core:jackson-databind") - - compileOnly("com.google.auto.service:auto-service") - annotationProcessor("com.google.auto.service:auto-service") -} diff --git a/agent/agent-profiler/agent-diagnostics-serialization/gradle.lockfile b/agent/agent-profiler/agent-diagnostics-serialization/gradle.lockfile deleted file mode 100644 index e2002aa05a7..00000000000 --- a/agent/agent-profiler/agent-diagnostics-serialization/gradle.lockfile +++ /dev/null @@ -1,13 +0,0 @@ -# This is a Gradle generated file for dependency locking. -# Manual edits can break the build and are not advised. -# This file is expected to be part of source control. -com.azure:azure-sdk-bom:1.2.29=runtimeClasspath -com.fasterxml.jackson:jackson-bom:2.18.1=runtimeClasspath -io.netty:netty-bom:4.1.114.Final=runtimeClasspath -io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom-alpha:2.9.0-alpha=runtimeClasspath -io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom:2.9.0=runtimeClasspath -io.opentelemetry:opentelemetry-bom-alpha:1.43.0-alpha=runtimeClasspath -io.opentelemetry:opentelemetry-bom:1.43.0=runtimeClasspath -org.junit:junit-bom:5.11.3=runtimeClasspath -org.testcontainers:testcontainers-bom:1.20.3=runtimeClasspath -empty= diff --git a/agent/agent-profiler/agent-diagnostics-serialization/src/main/java/com/microsoft/applicationinsights/diagnostics/collection/json/AlertApiModule.java b/agent/agent-profiler/agent-diagnostics-serialization/src/main/java/com/microsoft/applicationinsights/diagnostics/collection/json/AlertApiModule.java deleted file mode 100644 index bf06ff0fcce..00000000000 --- a/agent/agent-profiler/agent-diagnostics-serialization/src/main/java/com/microsoft/applicationinsights/diagnostics/collection/json/AlertApiModule.java +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.microsoft.applicationinsights.diagnostics.collection.json; - -import com.fasterxml.jackson.databind.module.SimpleModule; -import com.microsoft.applicationinsights.alerting.aiconfig.AlertingConfig; - -public class AlertApiModule extends SimpleModule { - public AlertApiModule() { - addEnumConfig(AlertingConfig.RequestFilterType.class); - addEnumConfig(AlertingConfig.RequestAggregationType.class); - addEnumConfig(AlertingConfig.RequestTriggerThresholdType.class); - addEnumConfig(AlertingConfig.RequestTriggerThrottlingType.class); - addEnumConfig(AlertingConfig.RequestAggregationType.class); - } - - private > void addEnumConfig(Class clazz) { - addSerializer(clazz, new LowerCaseEnumSerializers.LowerCaseEnumSerializer<>()); - addDeserializer(clazz, new LowerCaseEnumSerializers.LowerCaseEnumDeSerializer<>(clazz)); - } -} diff --git a/agent/agent-profiler/agent-diagnostics-serialization/src/main/java/com/microsoft/applicationinsights/diagnostics/collection/json/LowerCaseEnumSerializers.java b/agent/agent-profiler/agent-diagnostics-serialization/src/main/java/com/microsoft/applicationinsights/diagnostics/collection/json/LowerCaseEnumSerializers.java deleted file mode 100644 index d63dd31015c..00000000000 --- a/agent/agent-profiler/agent-diagnostics-serialization/src/main/java/com/microsoft/applicationinsights/diagnostics/collection/json/LowerCaseEnumSerializers.java +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.microsoft.applicationinsights.diagnostics.collection.json; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JsonDeserializer; -import com.fasterxml.jackson.databind.JsonSerializer; -import com.fasterxml.jackson.databind.SerializerProvider; -import java.io.IOException; -import java.util.Locale; - -public class LowerCaseEnumSerializers { - - private LowerCaseEnumSerializers() {} - - public static class LowerCaseEnumSerializer> extends JsonSerializer { - @Override - public void serialize(T value, JsonGenerator gen, SerializerProvider serializers) - throws IOException { - gen.writeString(value.name().toLowerCase(Locale.ROOT).replace("_", "-")); - } - } - - public static class LowerCaseEnumDeSerializer> extends JsonDeserializer { - - private final Class clazz; - - public LowerCaseEnumDeSerializer(Class clazz) { - this.clazz = clazz; - } - - @Override - public T deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { - return Enum.valueOf( - clazz, p.getValueAsString().toUpperCase(Locale.ROOT).replaceAll("-", "_")); - } - } -} diff --git a/agent/agent-profiler/agent-diagnostics/build.gradle.kts b/agent/agent-profiler/agent-diagnostics/build.gradle.kts index 5a790e52fc5..8aedc1966c9 100644 --- a/agent/agent-profiler/agent-diagnostics/build.gradle.kts +++ b/agent/agent-profiler/agent-diagnostics/build.gradle.kts @@ -8,15 +8,13 @@ if (project.properties.containsKey("publish-diagnostics")) { } dependencies { - implementation(project(":agent:agent-profiler:agent-diagnostics-serialization")) implementation(project(":agent:agent-profiler:agent-alerting-api")) implementation(project(":agent:agent-profiler:agent-diagnostics-api")) implementation(project(":agent:agent-profiler:agent-diagnostics-jfr")) compileOnly("org.slf4j:slf4j-api") - compileOnly("com.fasterxml.jackson.core:jackson-annotations") - compileOnly("com.fasterxml.jackson.core:jackson-databind") compileOnly("org.gradle.jfr.polyfill:jfr-polyfill:1.0.2") + compileOnly("com.azure:azure-json") compileOnly("com.google.auto.service:auto-service") annotationProcessor("com.google.auto.service:auto-service") diff --git a/agent/agent-profiler/agent-diagnostics/src/main/java/com/microsoft/applicationinsights/diagnostics/appinsights/CodeOptimizerDiagnosticEngineJfr.java b/agent/agent-profiler/agent-diagnostics/src/main/java/com/microsoft/applicationinsights/diagnostics/appinsights/CodeOptimizerDiagnosticEngineJfr.java index 73dd5dc9605..d3fd13487a1 100644 --- a/agent/agent-profiler/agent-diagnostics/src/main/java/com/microsoft/applicationinsights/diagnostics/appinsights/CodeOptimizerDiagnosticEngineJfr.java +++ b/agent/agent-profiler/agent-diagnostics/src/main/java/com/microsoft/applicationinsights/diagnostics/appinsights/CodeOptimizerDiagnosticEngineJfr.java @@ -3,16 +3,17 @@ package com.microsoft.applicationinsights.diagnostics.appinsights; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; +import com.azure.json.JsonProviders; +import com.azure.json.JsonWriter; import com.microsoft.applicationinsights.alerting.alert.AlertBreach; import com.microsoft.applicationinsights.diagnostics.DiagnosisResult; import com.microsoft.applicationinsights.diagnostics.DiagnosticEngine; -import com.microsoft.applicationinsights.diagnostics.collection.json.AlertApiModule; import com.microsoft.applicationinsights.diagnostics.jfr.AlertBreachJfrEvent; import com.microsoft.applicationinsights.diagnostics.jfr.CodeOptimizerDiagnosticsJfrInit; import com.microsoft.applicationinsights.diagnostics.jfr.MachineStats; import com.microsoft.applicationinsights.diagnostics.jfr.SystemStatsProvider; +import java.io.IOException; +import java.io.StringWriter; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Future; import java.util.concurrent.ScheduledExecutorService; @@ -30,14 +31,12 @@ public class CodeOptimizerDiagnosticEngineJfr implements DiagnosticEngine { LoggerFactory.getLogger(CodeOptimizerDiagnosticEngineJfr.class); public static final int SEMAPHORE_TIMEOUT_IN_SEC = 10; public static final long TIME_BEFORE_END_OF_PROFILE_TO_EMIT_EVENT = 10L; - private final ObjectMapper mapper; private final ScheduledExecutorService executorService; private final Semaphore semaphore = new Semaphore(1, false); private int thisPid; public CodeOptimizerDiagnosticEngineJfr(ScheduledExecutorService executorService) { this.executorService = executorService; - this.mapper = new ObjectMapper().registerModule(new AlertApiModule()); } @Override @@ -133,7 +132,7 @@ private void scheduleEmittingAlertBreachEvent(AlertBreach alert, long end) { TimeUnit.SECONDS); } - private void emitInfo(AlertBreach alert) { + private static void emitInfo(AlertBreach alert) { LOGGER.debug("Emitting Code Optimizer Diagnostic Event"); emitAlertBreachJfrEvent(alert); CodeOptimizerDiagnosticsJfrInit.emitCGroupData(); @@ -145,13 +144,14 @@ private static void emitMachineStats() { machineStats.commit(); } - private void emitAlertBreachJfrEvent(AlertBreach alert) { - try { - String serializedBreach = mapper.writeValueAsString(alert); - AlertBreachJfrEvent event = new AlertBreachJfrEvent(serializedBreach); + private static void emitAlertBreachJfrEvent(AlertBreach alert) { + try (StringWriter stringWriter = new StringWriter(); + JsonWriter writer = JsonProviders.createWriter(stringWriter)) { + alert.toJson(writer).flush(); + AlertBreachJfrEvent event = new AlertBreachJfrEvent().setAlertBreach(stringWriter.toString()); event.commit(); LOGGER.debug("Emitted Code Optimizer Diagnostic Event"); - } catch (JsonProcessingException e) { + } catch (IOException e) { LOGGER.error("Failed to create breach JFR event", e); } } diff --git a/agent/agent-profiler/agent-diagnostics/src/main/java/com/microsoft/applicationinsights/diagnostics/collection/jvm/ProcessData.java b/agent/agent-profiler/agent-diagnostics/src/main/java/com/microsoft/applicationinsights/diagnostics/collection/jvm/ProcessData.java index 21a136892ca..fde95b22ba2 100644 --- a/agent/agent-profiler/agent-diagnostics/src/main/java/com/microsoft/applicationinsights/diagnostics/collection/jvm/ProcessData.java +++ b/agent/agent-profiler/agent-diagnostics/src/main/java/com/microsoft/applicationinsights/diagnostics/collection/jvm/ProcessData.java @@ -3,9 +3,10 @@ package com.microsoft.applicationinsights.diagnostics.collection.jvm; -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; +import com.azure.json.JsonSerializable; +import com.azure.json.JsonWriter; import com.microsoft.applicationinsights.diagnostics.collection.libos.process.ProcessInfo; +import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -18,13 +19,13 @@ /** * Represents information about a running process. Also attempts to redact any sensitive arguments. */ -public class ProcessData implements ProcessInfo { +public class ProcessData implements ProcessInfo, JsonSerializable { - private final String name; - private final int pid; - private final String uid; + private String name; + private int pid; + private String uid = UUID.randomUUID().toString(); - @Nullable private final Map metaData; + @Nullable private Map metaData; private static final List SENSITIVE_PROPERTIES_ARGS = Arrays.asList( @@ -68,49 +69,81 @@ public static String sanetiseArg(String name) { return name; } + public ProcessData() {} + public ProcessData(String name, int pid) { - this(name, pid, UUID.randomUUID().toString()); + setName(name).setPid(pid); } public ProcessData(String name, int pid, Map metaData) { - this(name, pid, UUID.randomUUID().toString(), metaData); + setName(name).setPid(pid).setMetaData(metaData); } public ProcessData(String name, int pid, String uid) { - this(name, pid, uid, null); + setName(name).setPid(pid).setUid(uid); } public ProcessData(String name) { - this(sanetiseArg(name), -1, UUID.randomUUID().toString(), null); + setName(name).setPid(-1); } public ProcessData(ProcessInfo clone) { - this( - (clone == null ? "Unknown" : clone.getName()), - (clone == null ? -1 : clone.getPid()), - (clone == null ? UUID.randomUUID().toString() : clone.getUid()), - (clone == null ? null : clone.getMetaData())); - } - - @JsonCreator - public ProcessData( - @JsonProperty("name") String name, - @JsonProperty("pid") int pid, - @Nullable @JsonProperty("uid") String uid, - @Nullable @JsonProperty("metaData") Map metaData) { + setName(clone == null ? "Unknown" : clone.getName()) + .setPid(clone == null ? -1 : clone.getPid()) + .setUid(clone == null ? UUID.randomUUID().toString() : clone.getUid()) + .setMetaData(clone == null ? null : clone.getMetaData()); + } + + @Override + public String getName() { + return name; + } + + public ProcessData setName(String name) { this.name = sanetiseArg(name); + return this; + } + + @Override + public int getPid() { + return pid; + } + + public ProcessData setPid(int pid) { this.pid = pid; - if (uid == null) { - this.uid = UUID.randomUUID().toString(); - } else { - this.uid = uid; - } + return this; + } - if (metaData != null) { - this.metaData = Collections.unmodifiableMap(metaData); - } else { - this.metaData = null; - } + @Override + public String getUid() { + return uid; + } + + public ProcessData setUid(String uid) { + this.uid = uid; + return this; + } + + @Override + @Nullable + public Map getMetaData() { + return metaData; + } + + public ProcessData setMetaData(@Nullable Map metaData) { + this.metaData = metaData != null ? Collections.unmodifiableMap(metaData) : null; + return this; + } + + @Override + public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { + jsonWriter.writeStartObject(); + jsonWriter.writeStringField("name", name); + jsonWriter.writeIntField("pid", pid); + jsonWriter.writeStringField("uid", uid); + jsonWriter.writeMapField("metaData", metaData, JsonWriter::writeString); + jsonWriter.writeEndObject(); + return jsonWriter; } // @ExistsForTesting @@ -127,21 +160,6 @@ protected static ProcessData create(String name, int pid, @Nullable String uid) return new ProcessData(name, pid, uid); } - @Override - public String getName() { - return name; - } - - @Override - public int getPid() { - return pid; - } - - @Override - public String getUid() { - return uid; - } - @Override public int compareTo(ProcessInfo o) { return COMPARATOR.compare(this, o); @@ -178,10 +196,4 @@ public boolean equals(Object obj) { } return pid == other.pid; } - - @Override - @Nullable - public Map getMetaData() { - return metaData; - } } diff --git a/agent/agent-profiler/agent-diagnostics/src/main/java/com/microsoft/applicationinsights/diagnostics/collection/libos/hardware/MemoryInfo.java b/agent/agent-profiler/agent-diagnostics/src/main/java/com/microsoft/applicationinsights/diagnostics/collection/libos/hardware/MemoryInfo.java index 89f97928a22..732bc96a098 100644 --- a/agent/agent-profiler/agent-diagnostics/src/main/java/com/microsoft/applicationinsights/diagnostics/collection/libos/hardware/MemoryInfo.java +++ b/agent/agent-profiler/agent-diagnostics/src/main/java/com/microsoft/applicationinsights/diagnostics/collection/libos/hardware/MemoryInfo.java @@ -3,45 +3,64 @@ package com.microsoft.applicationinsights.diagnostics.collection.libos.hardware; -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; +import com.azure.json.JsonSerializable; +import com.azure.json.JsonWriter; +import java.io.IOException; -public class MemoryInfo { +public class MemoryInfo implements JsonSerializable { - private final long totalInKb; + private long totalInKb; - private final long freeInKb; + private long freeInKb; - private final long virtualMemoryTotalInKb; + private long virtualMemoryTotalInKb; - private final long virtualMemoryUsedInKb; - - @JsonCreator - public MemoryInfo( - @JsonProperty("totalInKB") long totalInKb, - @JsonProperty("freeInKB") long freeInKb, - @JsonProperty("virtualMemoryTotalInKB") long virtualMemoryTotalInKb, - @JsonProperty("virtualMemoryUsedInKB") long virtualMemoryUsedInKb) { - - this.totalInKb = totalInKb; - this.freeInKb = freeInKb; - this.virtualMemoryTotalInKb = virtualMemoryTotalInKb; - this.virtualMemoryUsedInKb = virtualMemoryUsedInKb; - } + private long virtualMemoryUsedInKb; public long getTotalInKb() { return totalInKb; } + public MemoryInfo setTotalInKb(long totalInKb) { + this.totalInKb = totalInKb; + return this; + } + public long getFreeInKb() { return freeInKb; } + public MemoryInfo setFreeInKb(long freeInKb) { + this.freeInKb = freeInKb; + return this; + } + public long getVirtualMemoryTotalInKb() { return virtualMemoryTotalInKb; } + public MemoryInfo setVirtualMemoryTotalInKb(long virtualMemoryTotalInKb) { + this.virtualMemoryTotalInKb = virtualMemoryTotalInKb; + return this; + } + public long getVirtualMemoryUsedInKb() { return virtualMemoryUsedInKb; } + + public MemoryInfo setVirtualMemoryUsedInKb(long virtualMemoryUsedInKb) { + this.virtualMemoryUsedInKb = virtualMemoryUsedInKb; + return this; + } + + @Override + public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { + jsonWriter.writeStartObject(); + jsonWriter.writeLongField("totalInKb", totalInKb); + jsonWriter.writeLongField("freeInKb", freeInKb); + jsonWriter.writeLongField("virtualMemoryTotalInKb", virtualMemoryTotalInKb); + jsonWriter.writeLongField("virtualMemoryUsedInKb", virtualMemoryUsedInKb); + jsonWriter.writeEndObject(); + return jsonWriter; + } } diff --git a/agent/agent-profiler/agent-diagnostics/src/main/java/com/microsoft/applicationinsights/diagnostics/collection/libos/os/linux/LinuxMemoryInfoReader.java b/agent/agent-profiler/agent-diagnostics/src/main/java/com/microsoft/applicationinsights/diagnostics/collection/libos/os/linux/LinuxMemoryInfoReader.java index 22f79f6b59e..29ca3e6109b 100644 --- a/agent/agent-profiler/agent-diagnostics/src/main/java/com/microsoft/applicationinsights/diagnostics/collection/libos/os/linux/LinuxMemoryInfoReader.java +++ b/agent/agent-profiler/agent-diagnostics/src/main/java/com/microsoft/applicationinsights/diagnostics/collection/libos/os/linux/LinuxMemoryInfoReader.java @@ -16,7 +16,12 @@ public class LinuxMemoryInfoReader extends TwoStepProcReader implements MemoryIn private int freeInKbIndex = -1; private int virtualMemoryTotalInKbIndex = -1; private int virtualMemoryUsedInKbIndex = -1; - private MemoryInfo memoryInfo = new MemoryInfo(-1, -1, -1, -1); + private MemoryInfo memoryInfo = + new MemoryInfo() + .setTotalInKb(-1) + .setFreeInKb(-1) + .setVirtualMemoryTotalInKb(-1) + .setVirtualMemoryUsedInKb(-1); public LinuxMemoryInfoReader() { super(new File(MEMINFO)); @@ -46,7 +51,11 @@ public MemoryInfo readMemoryInfo(String content) { long virtualMemoryTotalInKb = readMemoryNumber(lines[virtualMemoryTotalInKbIndex]); long virtualMemoryUsedInKb = readMemoryNumber(lines[virtualMemoryUsedInKbIndex]); - return new MemoryInfo(totalInKb, freeInKb, virtualMemoryTotalInKb, virtualMemoryUsedInKb); + return new MemoryInfo() + .setTotalInKb(totalInKb) + .setFreeInKb(freeInKb) + .setVirtualMemoryTotalInKb(virtualMemoryTotalInKb) + .setVirtualMemoryUsedInKb(virtualMemoryUsedInKb); } private static long readMemoryNumber(String line) { diff --git a/agent/agent-profiler/agent-diagnostics/src/main/java/com/microsoft/applicationinsights/diagnostics/collection/libos/os/nop/NoOpMemoryInfoReader.java b/agent/agent-profiler/agent-diagnostics/src/main/java/com/microsoft/applicationinsights/diagnostics/collection/libos/os/nop/NoOpMemoryInfoReader.java index 9de97fe6626..7d195752f16 100644 --- a/agent/agent-profiler/agent-diagnostics/src/main/java/com/microsoft/applicationinsights/diagnostics/collection/libos/os/nop/NoOpMemoryInfoReader.java +++ b/agent/agent-profiler/agent-diagnostics/src/main/java/com/microsoft/applicationinsights/diagnostics/collection/libos/os/nop/NoOpMemoryInfoReader.java @@ -17,7 +17,11 @@ public void update() throws OperatingSystemInteractionException {} @Override public MemoryInfo getMemoryInfo() { - return new MemoryInfo(-1, -1, -1, -1); + return new MemoryInfo() + .setTotalInKb(-1) + .setFreeInKb(-1) + .setVirtualMemoryTotalInKb(-1) + .setVirtualMemoryUsedInKb(-1); } @Override diff --git a/agent/agent-profiler/agent-diagnostics/src/main/java/com/microsoft/applicationinsights/diagnostics/collection/libos/process/ProcessInfo.java b/agent/agent-profiler/agent-diagnostics/src/main/java/com/microsoft/applicationinsights/diagnostics/collection/libos/process/ProcessInfo.java index ba562d4b19b..8aebcf94887 100644 --- a/agent/agent-profiler/agent-diagnostics/src/main/java/com/microsoft/applicationinsights/diagnostics/collection/libos/process/ProcessInfo.java +++ b/agent/agent-profiler/agent-diagnostics/src/main/java/com/microsoft/applicationinsights/diagnostics/collection/libos/process/ProcessInfo.java @@ -3,16 +3,8 @@ package com.microsoft.applicationinsights.diagnostics.collection.libos.process; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonTypeInfo; import java.util.Map; -@JsonTypeInfo( - use = JsonTypeInfo.Id.NAME, - include = JsonTypeInfo.As.PROPERTY, - property = "type", - visible = true) -@JsonIgnoreProperties(ignoreUnknown = true) public interface ProcessInfo extends Comparable { String getName(); diff --git a/agent/agent-profiler/agent-diagnostics/src/main/java/com/microsoft/applicationinsights/diagnostics/jfr/CodeOptimizerDiagnosticsJfrInit.java b/agent/agent-profiler/agent-diagnostics/src/main/java/com/microsoft/applicationinsights/diagnostics/jfr/CodeOptimizerDiagnosticsJfrInit.java index 6955a2a6be0..c24a3728bfc 100644 --- a/agent/agent-profiler/agent-diagnostics/src/main/java/com/microsoft/applicationinsights/diagnostics/jfr/CodeOptimizerDiagnosticsJfrInit.java +++ b/agent/agent-profiler/agent-diagnostics/src/main/java/com/microsoft/applicationinsights/diagnostics/jfr/CodeOptimizerDiagnosticsJfrInit.java @@ -38,7 +38,7 @@ private static Runnable emitTelemetry(SystemStatsReader statsReader) { List telemetry = statsReader.readTelemetry(); if (telemetry != null && telemetry.size() > 0) { - new Telemetry(telemetry).commit(); + new Telemetry().setTelemetry(telemetry).commit(); } else { logFailure("No telemetry data present", null, telemetryFailureLogCount); } diff --git a/agent/agent-profiler/agent-diagnostics/src/main/java/com/microsoft/applicationinsights/diagnostics/jfr/SystemStatsProvider.java b/agent/agent-profiler/agent-diagnostics/src/main/java/com/microsoft/applicationinsights/diagnostics/jfr/SystemStatsProvider.java index 525cb486544..38a361a617a 100644 --- a/agent/agent-profiler/agent-diagnostics/src/main/java/com/microsoft/applicationinsights/diagnostics/jfr/SystemStatsProvider.java +++ b/agent/agent-profiler/agent-diagnostics/src/main/java/com/microsoft/applicationinsights/diagnostics/jfr/SystemStatsProvider.java @@ -36,7 +36,6 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Supplier; -import javax.annotation.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -74,10 +73,12 @@ public static void init(int thisPid) { } } + @SuppressWarnings("unchecked") private static T getSingleton(Class clazz) { return (T) singletons.get(clazz).get(); } + @SuppressWarnings("unchecked") private static T getSingleton(Class clazz, Supplier supplier) { AtomicReference current = (AtomicReference) singletons.get(clazz); @@ -110,12 +111,14 @@ public static CGroupData getCGroupData() { () -> { try { CGroupDataReader reader = buildCGroupDataReader(); - return new CGroupData( - reader.getKmemLimit(), - reader.getMemoryLimit(), - reader.getMemorySoftLimit(), - reader.getCpuLimit(), - reader.getCpuPeriod()); + CGroupData data = new CGroupData(); + + return data.setKmemLimit(reader.getKmemLimit()) + .setMemoryLimit(reader.getMemoryLimit()) + .setMemorySoftLimit(reader.getMemorySoftLimit()) + .setCpuLimit(reader.getCpuLimit()) + .setCpuPeriod(reader.getCpuPeriod()); + } catch (RuntimeException | OperatingSystemInteractionException e) { LOGGER.warn("No CGroup data present"); return null; @@ -127,9 +130,9 @@ public static MachineStats getMachineStats() { return getSingleton( MachineStats.class, () -> - new MachineStats( - getCalibration().getContextSwitchingRate(), - new RuntimeCoreCounter().getCoreCount())); + new MachineStats() + .setContextSwitchesPerMs(getCalibration().getContextSwitchingRate()) + .setCoreCount(new RuntimeCoreCounter().getCoreCount())); } private static Calibration getCalibration() { @@ -170,7 +173,6 @@ private static CGroupDataReader buildCGroupDataReader() { } } - @Nullable @SuppressWarnings("checkstyle:AbbreviationAsWordInName") private static ProcessDumper getProcessDumper() { ThisPidSupplier pidSupplier = getSingleton(ThisPidSupplier.class); diff --git a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/profiler/config/ProfilerConfiguration.java b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/profiler/config/ProfilerConfiguration.java index 30090a0ef25..2c5951c85ab 100644 --- a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/profiler/config/ProfilerConfiguration.java +++ b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/profiler/config/ProfilerConfiguration.java @@ -3,73 +3,202 @@ package com.microsoft.applicationinsights.agent.internal.profiler.config; -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; +import com.azure.json.JsonReader; +import com.azure.json.JsonSerializable; +import com.azure.json.JsonToken; +import com.azure.json.JsonWriter; import com.fasterxml.jackson.databind.util.StdDateFormat; -import com.google.auto.value.AutoValue; +import com.microsoft.applicationinsights.agent.internal.profiler.util.TimestampContract; import com.microsoft.applicationinsights.alerting.aiconfig.AlertingConfig; +import java.io.IOException; import java.text.ParseException; import java.util.Date; import java.util.List; import javax.annotation.Nullable; -@AutoValue -public abstract class ProfilerConfiguration { +public class ProfilerConfiguration implements JsonSerializable { public static final Date DEFAULT_DATE; + // TODO find an alternative to com.fasterxml.jackson.databind.util.StdDateFormat + private static final StdDateFormat STD_DATE_FORMAT; static { + STD_DATE_FORMAT = new StdDateFormat(); Date defaultDate; try { - defaultDate = new StdDateFormat().parse("0001-01-01T00:00:00+00:00"); + defaultDate = STD_DATE_FORMAT.parse("0001-01-01T00:00:00+00:00"); } catch (ParseException e) { - // will not happen defaultDate = null; } DEFAULT_DATE = defaultDate; } - @JsonCreator - public static ProfilerConfiguration create( - @JsonProperty("lastModified") Date lastModified, - @JsonProperty("enabled") boolean enabled, - @JsonProperty("collectionPlan") String collectionPlan, - @JsonProperty("cpuTriggerConfiguration") String cpuTriggerConfiguration, - @JsonProperty("memoryTriggerConfiguration") String memoryTriggerConfiguration, - @JsonProperty("defaultConfiguration") String defaultConfiguration, - @JsonProperty("requestTriggerConfiguration") - List requestTriggerConfiguration) { - - return new AutoValue_ProfilerConfiguration( - lastModified, - enabled, - collectionPlan, - cpuTriggerConfiguration, - memoryTriggerConfiguration, - defaultConfiguration, - requestTriggerConfiguration); - } + private String id; + private Date lastModified; + private Date enabledLastModified; + private boolean enabled; + private String collectionPlan; + private String cpuTriggerConfiguration; + private String memoryTriggerConfiguration; + private String defaultConfiguration; + private List requestTriggerConfiguration; public boolean hasBeenConfigured() { return getLastModified().compareTo(DEFAULT_DATE) != 0; } - public abstract Date getLastModified(); + public String id() { + return id; + } + + public ProfilerConfiguration setId(String id) { + this.id = id; + return this; + } + + public Date getLastModified() { + return lastModified; + } + + public ProfilerConfiguration setLastModified(Date lastModified) { + this.lastModified = lastModified; + return this; + } + + public Date getEnabledLastModified() { + return enabledLastModified; + } - public abstract boolean isEnabled(); + public ProfilerConfiguration setEnabledLastModified(Date enabledLastModified) { + this.enabledLastModified = enabledLastModified; + return this; + } + + public boolean isEnabled() { + return enabled; + } + + public ProfilerConfiguration setEnabled(boolean enabled) { + this.enabled = enabled; + return this; + } @Nullable - public abstract String getCollectionPlan(); + public String getCollectionPlan() { + return collectionPlan; + } + + public ProfilerConfiguration setCollectionPlan(String collectionPlan) { + this.collectionPlan = collectionPlan; + return this; + } @Nullable - public abstract String getCpuTriggerConfiguration(); + public String getCpuTriggerConfiguration() { + return cpuTriggerConfiguration; + } + + public ProfilerConfiguration setCpuTriggerConfiguration(String cpuTriggerConfiguration) { + this.cpuTriggerConfiguration = cpuTriggerConfiguration; + return this; + } @Nullable - public abstract String getMemoryTriggerConfiguration(); + public String getMemoryTriggerConfiguration() { + return memoryTriggerConfiguration; + } + + public ProfilerConfiguration setMemoryTriggerConfiguration(String memoryTriggerConfiguration) { + this.memoryTriggerConfiguration = memoryTriggerConfiguration; + return this; + } @Nullable - public abstract String getDefaultConfiguration(); + public String getDefaultConfiguration() { + return defaultConfiguration; + } + + public ProfilerConfiguration setDefaultConfiguration(String defaultConfiguration) { + this.defaultConfiguration = defaultConfiguration; + return this; + } @Nullable - public abstract List getRequestTriggerConfiguration(); + public List getRequestTriggerConfiguration() { + return requestTriggerConfiguration; + } + + public ProfilerConfiguration setRequestTriggerConfiguration( + List requestTriggerConfiguration) { + this.requestTriggerConfiguration = requestTriggerConfiguration; + return this; + } + + @Override + public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { + jsonWriter.writeStartObject(); + jsonWriter.writeStringField("id", id); + jsonWriter.writeStringField("lastModified", STD_DATE_FORMAT.format(lastModified)); + jsonWriter.writeStringField( + "enabledLastModified", TimestampContract.timestampToString(enabledLastModified)); + jsonWriter.writeBooleanField("enabled", enabled); + jsonWriter.writeStringField("collectionPlan", collectionPlan); + jsonWriter.writeStringField("cpuTriggerConfiguration", cpuTriggerConfiguration); + jsonWriter.writeStringField("memoryTriggerConfiguration", memoryTriggerConfiguration); + jsonWriter.writeStringField("defaultConfiguration", defaultConfiguration); + jsonWriter.writeStartArray("requestTriggerConfiguration"); + for (AlertingConfig.RequestTrigger trigger : requestTriggerConfiguration) { + trigger.toJson(jsonWriter); + } + jsonWriter.writeEndArray(); + jsonWriter.writeEndObject(); + return jsonWriter; + } + + public static ProfilerConfiguration fromJson(JsonReader jsonReader) throws IOException { + return jsonReader.readObject( + reader -> { + ProfilerConfiguration deserializedProfilerConfiguration = new ProfilerConfiguration(); + while (reader.nextToken() != JsonToken.END_OBJECT) { + reader.nextToken(); + String fieldName = reader.getFieldName(); + if ("id".equals(fieldName)) { + String id = reader.getString(); + deserializedProfilerConfiguration.setId(id); + } else if ("lastModified".equals(fieldName)) { + String lastModified = reader.getString(); + try { + deserializedProfilerConfiguration.setLastModified( + new StdDateFormat().parse(lastModified)); + } catch (ParseException ignored) { + deserializedProfilerConfiguration.setLastModified(DEFAULT_DATE); + } + } else if ("enabledLastModified".equals(fieldName)) { + String enabledLastModified = reader.getString(); + try { + deserializedProfilerConfiguration.setEnabledLastModified( + STD_DATE_FORMAT.parse(enabledLastModified)); + } catch (ParseException ignored) { + deserializedProfilerConfiguration.setEnabledLastModified(DEFAULT_DATE); + } + } else if ("enabled".equals(fieldName)) { + deserializedProfilerConfiguration.setEnabled(reader.getBoolean()); + } else if ("collectionPlan".equals(fieldName)) { + deserializedProfilerConfiguration.setCollectionPlan(reader.getString()); + } else if ("cpuTriggerConfiguration".equals(fieldName)) { + deserializedProfilerConfiguration.setCpuTriggerConfiguration(reader.getString()); + } else if ("memoryTriggerConfiguration".equals(fieldName)) { + deserializedProfilerConfiguration.setMemoryTriggerConfiguration(reader.getString()); + } else if ("defaultConfiguration".equals(fieldName)) { + deserializedProfilerConfiguration.setDefaultConfiguration(reader.getString()); + } else if ("requestTriggerConfiguration".equals(fieldName)) { + deserializedProfilerConfiguration.setRequestTriggerConfiguration( + reader.readArray(AlertingConfig.RequestTrigger::fromJson)); + } else { + reader.skipChildren(); + } + } + return deserializedProfilerConfiguration; + }); + } } diff --git a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/profiler/service/ArtifactAcceptedResponse.java b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/profiler/service/ArtifactAcceptedResponse.java index 3233bffb6b4..33f44b4f48a 100644 --- a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/profiler/service/ArtifactAcceptedResponse.java +++ b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/profiler/service/ArtifactAcceptedResponse.java @@ -3,29 +3,87 @@ package com.microsoft.applicationinsights.agent.internal.profiler.service; -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.google.auto.value.AutoValue; +import com.azure.json.JsonReader; +import com.azure.json.JsonSerializable; +import com.azure.json.JsonToken; +import com.azure.json.JsonWriter; +import java.io.IOException; /** Result of uploading an artifact to service profiler. */ -@AutoValue -public abstract class ArtifactAcceptedResponse { +public class ArtifactAcceptedResponse implements JsonSerializable { - @JsonCreator - public static ArtifactAcceptedResponse create( - @JsonProperty("acceptedTime") String acceptedTime, - @JsonProperty("blobUri") String blobUri, - @JsonProperty("correlationId") String correlationId, - @JsonProperty("stampId") String stampId) { + private String acceptedTime; + private String stampId; + private String correlationId; + private String blobUri; - return new AutoValue_ArtifactAcceptedResponse(acceptedTime, stampId, correlationId, blobUri); + public String getAcceptedTime() { + return acceptedTime; } - public abstract String getAcceptedTime(); + public ArtifactAcceptedResponse setAcceptedTime(String acceptedTime) { + this.acceptedTime = acceptedTime; + return this; + } + + public String getStampId() { + return stampId; + } + + public ArtifactAcceptedResponse setStampId(String stampId) { + this.stampId = stampId; + return this; + } + + public String getCorrelationId() { + return correlationId; + } - public abstract String getStampId(); + public ArtifactAcceptedResponse setCorrelationId(String correlationId) { + this.correlationId = correlationId; + return this; + } + + public String getBlobUri() { + return blobUri; + } - public abstract String getCorrelationId(); + public ArtifactAcceptedResponse setBlobUri(String blobUri) { + this.blobUri = blobUri; + return this; + } - public abstract String getBlobUri(); + @Override + public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { + jsonWriter.writeStartObject(); + jsonWriter.writeStringField("acceptedTime", acceptedTime); + jsonWriter.writeStringField("stampId", stampId); + jsonWriter.writeStringField("correlationId", correlationId); + jsonWriter.writeStringField("blobUri", blobUri); + jsonWriter.writeEndObject(); + return jsonWriter; + } + + public static ArtifactAcceptedResponse fromJson(JsonReader jsonReader) throws IOException { + return jsonReader.readObject( + reader -> { + ArtifactAcceptedResponse deserializedArtifactAcceptedResponse = + new ArtifactAcceptedResponse(); + while (reader.nextToken() != JsonToken.END_OBJECT) { + String fieldName = reader.getFieldName(); + if ("acceptedTime".equals(fieldName)) { + deserializedArtifactAcceptedResponse.setAcceptedTime(reader.getString()); + } else if ("stampId".equals(fieldName)) { + deserializedArtifactAcceptedResponse.setStampId(reader.getString()); + } else if ("correlationId".equals(fieldName)) { + deserializedArtifactAcceptedResponse.setCorrelationId(reader.getString()); + } else if ("blobUri".equals(fieldName)) { + deserializedArtifactAcceptedResponse.setBlobUri(reader.getString()); + } else { + reader.skipChildren(); + } + } + return deserializedArtifactAcceptedResponse; + }); + } } diff --git a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/profiler/service/ServiceProfilerClient.java b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/profiler/service/ServiceProfilerClient.java index d1d787e0b78..02c79790a9f 100644 --- a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/profiler/service/ServiceProfilerClient.java +++ b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/profiler/service/ServiceProfilerClient.java @@ -8,8 +8,8 @@ import com.azure.core.http.HttpPipeline; import com.azure.core.http.HttpRequest; import com.azure.core.http.HttpResponse; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.ObjectMapper; +import com.azure.json.JsonProviders; +import com.azure.json.JsonReader; import com.microsoft.applicationinsights.agent.internal.profiler.config.ProfilerConfiguration; import com.microsoft.applicationinsights.agent.internal.profiler.util.TimestampContract; import java.io.IOException; @@ -27,9 +27,6 @@ public class ServiceProfilerClient { private static final Logger logger = LoggerFactory.getLogger(ServiceProfilerClient.class); - private static final ObjectMapper mapper = - new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - private static final String PROFILER_API_PREFIX = "api/profileragent/v4"; private static final String INSTRUMENTATION_KEY_PARAMETER = "iKey"; @@ -108,9 +105,8 @@ public Mono reportUploadFinish( // this shouldn't happen, the mono should complete with a response or a failure return Mono.error(new AssertionError("response body mono returned empty")); } - try { - ArtifactAcceptedResponse data = - mapper.readValue(json, ArtifactAcceptedResponse.class); + try (JsonReader reader = JsonProviders.createReader(json)) { + ArtifactAcceptedResponse data = ArtifactAcceptedResponse.fromJson(reader); if (data == null) { return Mono.error(new IllegalStateException("Failed to deserialize response")); } @@ -165,8 +161,8 @@ private static Mono handle(HttpResponse response, URL req .getBodyAsString() .flatMap( body -> { - try { - return Mono.just(mapper.readValue(body, ProfilerConfiguration.class)); + try (JsonReader jsonReader = JsonProviders.createReader(body)) { + return Mono.just(ProfilerConfiguration.fromJson(jsonReader)); } catch (IOException e) { return Mono.error(e); } diff --git a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/profiler/triggers/RequestAlertPipelineBuilder.java b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/profiler/triggers/RequestAlertPipelineBuilder.java index 419a61ca362..df7b07f0fbc 100644 --- a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/profiler/triggers/RequestAlertPipelineBuilder.java +++ b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/profiler/triggers/RequestAlertPipelineBuilder.java @@ -70,40 +70,45 @@ static AlertingConfig.RequestTrigger buildRequestTriggerConfiguration( AlertingConfig.RequestTriggerType.valueOf(configuration.type.name()); AlertingConfig.RequestFilter filter = - new AlertingConfig.RequestFilter( - AlertingConfig.RequestFilterType.valueOf(configuration.filter.type.name()), - configuration.filter.value); + new AlertingConfig.RequestFilter() + .setType(AlertingConfig.RequestFilterType.valueOf(configuration.filter.type.name())) + .setValue(configuration.filter.value); AlertingConfig.RequestAggregationConfig requestAggregationConfig = - new AlertingConfig.RequestAggregationConfig( - configuration.aggregation.configuration.thresholdMillis, - configuration.aggregation.configuration.minimumSamples); + new AlertingConfig.RequestAggregationConfig() + .setThresholdMillis(configuration.aggregation.configuration.thresholdMillis) + .setMinimumSamples(configuration.aggregation.configuration.minimumSamples); AlertingConfig.RequestAggregation aggregation = - new AlertingConfig.RequestAggregation( - AlertingConfig.RequestAggregationType.valueOf(configuration.aggregation.type.name()), - configuration.aggregation.windowSizeMillis, - requestAggregationConfig); + new AlertingConfig.RequestAggregation() + .setType( + AlertingConfig.RequestAggregationType.valueOf( + configuration.aggregation.type.name())) + .setWindowSizeMillis(configuration.aggregation.windowSizeMillis) + .setConfiguration(requestAggregationConfig); AlertingConfig.RequestTriggerThreshold requestTriggerThreshold = - new AlertingConfig.RequestTriggerThreshold( - AlertingConfig.RequestTriggerThresholdType.valueOf(configuration.threshold.type.name()), - configuration.threshold.value); + new AlertingConfig.RequestTriggerThreshold() + .setType( + AlertingConfig.RequestTriggerThresholdType.valueOf( + configuration.threshold.type.name())) + .setValue(configuration.threshold.value); AlertingConfig.RequestTriggerThrottling throttling = - new AlertingConfig.RequestTriggerThrottling( - AlertingConfig.RequestTriggerThrottlingType.valueOf( - configuration.throttling.type.name()), - configuration.throttling.value); - - return new AlertingConfig.RequestTrigger( - configuration.name, - type, - filter, - aggregation, - requestTriggerThreshold, - throttling, - configuration.profileDuration); + new AlertingConfig.RequestTriggerThrottling() + .setType( + AlertingConfig.RequestTriggerThrottlingType.valueOf( + configuration.throttling.type.name())) + .setValue(configuration.throttling.value); + + return new AlertingConfig.RequestTrigger() + .setName(configuration.name) + .setType(type) + .setFilter(filter) + .setAggregation(aggregation) + .setThreshold(requestTriggerThreshold) + .setThrottling(throttling) + .setProfileDuration(configuration.profileDuration); } @Nullable diff --git a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/profiler/util/TimestampContract.java b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/profiler/util/TimestampContract.java index 0519c3b73c9..316f7213957 100644 --- a/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/profiler/util/TimestampContract.java +++ b/agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/profiler/util/TimestampContract.java @@ -22,7 +22,7 @@ */ public final class TimestampContract { // Cant use ISO_INSTANT as it does not pad the nanos to 7 figures - private static final DateTimeFormatter FORMATTER = + public static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.nX", Locale.ROOT); private static final Pattern TIMESTAMP_PATTERN = Pattern.compile(".*\\.([0-9]+)Z$"); diff --git a/agent/agent-tooling/src/test/java/com/microsoft/applicationinsights/agent/internal/profiler/ProfilingInitializerTest.java b/agent/agent-tooling/src/test/java/com/microsoft/applicationinsights/agent/internal/profiler/ProfilingInitializerTest.java index c2d838440f3..6acc8cf0a19 100644 --- a/agent/agent-tooling/src/test/java/com/microsoft/applicationinsights/agent/internal/profiler/ProfilingInitializerTest.java +++ b/agent/agent-tooling/src/test/java/com/microsoft/applicationinsights/agent/internal/profiler/ProfilingInitializerTest.java @@ -166,28 +166,28 @@ public Collection runTests() { @NotNull private static ProfilerConfiguration unconfiguredState() { - return ProfilerConfiguration.create( - ProfilerConfiguration.DEFAULT_DATE, - true, - "", - "--cpu-threshold 80 --cpu-trigger-profilingDuration 120 --cpu-trigger-cooldown 14400 --cpu-trigger-enabled true", - "--memory-threshold 80 --memory-trigger-profilingDuration 120 --memory-trigger-cooldown 14400 --memory-trigger-enabled true", - null, - null); + return new ProfilerConfiguration() + .setLastModified(ProfilerConfiguration.DEFAULT_DATE) + .setEnabled(true) + .setCollectionPlan("") + .setCpuTriggerConfiguration( + "--cpu-threshold 80 --cpu-trigger-profilingDuration 120 --cpu-trigger-cooldown 14400 --cpu-trigger-enabled true") + .setMemoryTriggerConfiguration( + "--memory-threshold 80 --memory-trigger-profilingDuration 120 --memory-trigger-cooldown 14400 --memory-trigger-enabled true"); } @NotNull private static ProfilerConfiguration userConfiguredTriggersState(boolean triggersEnabled) { - return ProfilerConfiguration.create( - new Date(Instant.now().toEpochMilli()), - true, - "", - "--cpu-threshold 80 --cpu-trigger-profilingDuration 120 --cpu-trigger-cooldown 14400 --cpu-trigger-enabled " - + triggersEnabled, - "--memory-threshold 80 --memory-trigger-profilingDuration 120 --memory-trigger-cooldown 14400 --memory-trigger-enabled " - + triggersEnabled, - null, - null); + return new ProfilerConfiguration() + .setLastModified(new Date(Instant.now().toEpochMilli())) + .setEnabled(true) + .setCollectionPlan("") + .setCpuTriggerConfiguration( + "--cpu-threshold 80 --cpu-trigger-profilingDuration 120 --cpu-trigger-cooldown 14400 --cpu-trigger-enabled " + + triggersEnabled) + .setMemoryTriggerConfiguration( + "--memory-threshold 80 --memory-trigger-profilingDuration 120 --memory-trigger-cooldown 14400 --memory-trigger-enabled " + + triggersEnabled); } @NotNull @@ -200,18 +200,19 @@ private static ProfilerConfiguration profileNowState( expiration = Instant.now().plus(100, ChronoUnit.SECONDS); } - return ProfilerConfiguration.create( - new Date(Instant.now().minus(10, ChronoUnit.SECONDS).toEpochMilli()), - true, - "--single --mode immediate --immediate-profiling-duration 120 --expiration " - + toBinaryDate(expiration) - + " --settings-moniker a-settings-moniker", - "--cpu-threshold 80 --cpu-trigger-profilingDuration 120 --cpu-trigger-cooldown 14400 --cpu-trigger-enabled " - + triggersEnabled, - "--memory-threshold 80 --memory-trigger-profilingDuration 120 --memory-trigger-cooldown 14400 --memory-trigger-enabled " - + triggersEnabled, - null, - null); + return new ProfilerConfiguration() + .setLastModified(new Date(Instant.now().minus(10, ChronoUnit.SECONDS).toEpochMilli())) + .setEnabled(true) + .setCollectionPlan( + "--single --mode immediate --immediate-profiling-duration 120 --expiration " + + toBinaryDate(expiration) + + " --settings-moniker a-settings-moniker") + .setCpuTriggerConfiguration( + "--cpu-threshold 80 --cpu-trigger-profilingDuration 120 --cpu-trigger-cooldown 14400 --cpu-trigger-enabled " + + triggersEnabled) + .setMemoryTriggerConfiguration( + "--memory-threshold 80 --memory-trigger-profilingDuration 120 --memory-trigger-cooldown 14400 --memory-trigger-enabled " + + triggersEnabled); } @SuppressWarnings("DirectInvocationOnMock") diff --git a/agent/agent-tooling/src/test/java/com/microsoft/applicationinsights/agent/internal/profiler/config/ConfigServiceTest.java b/agent/agent-tooling/src/test/java/com/microsoft/applicationinsights/agent/internal/profiler/config/ConfigServiceTest.java index 6e84a98178b..b02b0672cdc 100644 --- a/agent/agent-tooling/src/test/java/com/microsoft/applicationinsights/agent/internal/profiler/config/ConfigServiceTest.java +++ b/agent/agent-tooling/src/test/java/com/microsoft/applicationinsights/agent/internal/profiler/config/ConfigServiceTest.java @@ -11,7 +11,7 @@ import com.azure.core.http.HttpPipelineBuilder; import com.azure.core.test.TestBase; import com.azure.core.test.TestMode; -import com.fasterxml.jackson.core.JsonParseException; +import com.azure.json.implementation.jackson.core.JsonParseException; import com.microsoft.applicationinsights.agent.internal.profiler.service.ServiceProfilerClient; import java.io.IOException; import java.net.MalformedURLException; diff --git a/agent/agent-tooling/src/test/java/com/microsoft/applicationinsights/agent/internal/profiler/triggers/AlertConfigParserTest.java b/agent/agent-tooling/src/test/java/com/microsoft/applicationinsights/agent/internal/profiler/triggers/AlertConfigParserTest.java index 63b55eb22c8..91541b4c1ca 100644 --- a/agent/agent-tooling/src/test/java/com/microsoft/applicationinsights/agent/internal/profiler/triggers/AlertConfigParserTest.java +++ b/agent/agent-tooling/src/test/java/com/microsoft/applicationinsights/agent/internal/profiler/triggers/AlertConfigParserTest.java @@ -78,20 +78,31 @@ void saneDataIsParsed() { @Test void requestTriggerIsBuilt() { AlertingConfig.RequestTrigger requestTrigger = - new AlertingConfig.RequestTrigger( - "test", - AlertingConfig.RequestTriggerType.LATENCY, - new AlertingConfig.RequestFilter( - AlertingConfig.RequestFilterType.NAME_REGEX, "/api/users/.*"), - new AlertingConfig.RequestAggregation( - AlertingConfig.RequestAggregationType.BREACH_RATIO, - 7000, - new AlertingConfig.RequestAggregationConfig(10000, 10)), - new AlertingConfig.RequestTriggerThreshold( - AlertingConfig.RequestTriggerThresholdType.GREATER_THAN, 0.75f), - new AlertingConfig.RequestTriggerThrottling( - AlertingConfig.RequestTriggerThrottlingType.FIXED_DURATION_COOLDOWN, 1800), - 10); + new AlertingConfig.RequestTrigger() + .setName("test") + .setType(AlertingConfig.RequestTriggerType.LATENCY) + .setFilter( + new AlertingConfig.RequestFilter() + .setType(AlertingConfig.RequestFilterType.NAME_REGEX) + .setValue("/api/users/.*")) + .setAggregation( + new AlertingConfig.RequestAggregation() + .setType(AlertingConfig.RequestAggregationType.BREACH_RATIO) + .setWindowSizeMillis(7000) + .setConfiguration( + new AlertingConfig.RequestAggregationConfig() + .setThresholdMillis(10000) + .setMinimumSamples(10))) + .setThreshold( + new AlertingConfig.RequestTriggerThreshold() + .setType(AlertingConfig.RequestTriggerThresholdType.GREATER_THAN) + .setValue(0.75f)) + .setThrottling( + new AlertingConfig.RequestTriggerThrottling() + .setType(AlertingConfig.RequestTriggerThrottlingType.FIXED_DURATION_COOLDOWN) + .setValue(1800)) + .setProfileDuration(10); + List requestTriggers = new ArrayList<>(); requestTriggers.add(requestTrigger); diff --git a/agent/agent-tooling/src/test/java/com/microsoft/applicationinsights/agent/internal/profiler/triggers/RequestAlertPipelineBuilderTest.java b/agent/agent-tooling/src/test/java/com/microsoft/applicationinsights/agent/internal/profiler/triggers/RequestAlertPipelineBuilderTest.java index ceb34ff66ae..106a5445a56 100644 --- a/agent/agent-tooling/src/test/java/com/microsoft/applicationinsights/agent/internal/profiler/triggers/RequestAlertPipelineBuilderTest.java +++ b/agent/agent-tooling/src/test/java/com/microsoft/applicationinsights/agent/internal/profiler/triggers/RequestAlertPipelineBuilderTest.java @@ -3,12 +3,14 @@ package com.microsoft.applicationinsights.agent.internal.profiler.triggers; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; +import com.azure.json.JsonProviders; +import com.azure.json.JsonReader; +import com.azure.json.JsonWriter; import com.microsoft.applicationinsights.agent.internal.configuration.Configuration; import com.microsoft.applicationinsights.agent.internal.profiler.testutil.TestTimeSource; import com.microsoft.applicationinsights.alerting.aiconfig.AlertingConfig; +import java.io.IOException; +import java.io.StringWriter; import java.time.Instant; import java.util.List; import java.util.stream.Collectors; @@ -21,24 +23,47 @@ public class RequestAlertPipelineBuilderTest { @Test - public void configurationIsCorrectlyDuplicated() throws JsonProcessingException { - Configuration.RequestTrigger triggerConfig = new Configuration.RequestTrigger(); - triggerConfig.filter.type = Configuration.RequestFilterType.NAME_REGEX; - triggerConfig.filter.value = "foo.*"; - triggerConfig.threshold.value = 0.75f; + public void configurationIsCorrectlyDuplicated() throws IOException { + Configuration.RequestTrigger expectedRequestTrigger = new Configuration.RequestTrigger(); + expectedRequestTrigger.filter.type = Configuration.RequestFilterType.NAME_REGEX; + expectedRequestTrigger.filter.value = "foo.*"; + expectedRequestTrigger.threshold.value = 0.75f; TestTimeSource timeSource = new TestTimeSource(); timeSource.setNow(Instant.EPOCH); AlertingConfig.RequestTrigger config = - RequestAlertPipelineBuilder.buildRequestTriggerConfiguration(triggerConfig); + RequestAlertPipelineBuilder.buildRequestTriggerConfiguration(expectedRequestTrigger); - ObjectMapper mapper = new ObjectMapper(); - String configurationStr = mapper.writeValueAsString(triggerConfig); - String alertingConfigStr = mapper.writeValueAsString(config); - ; + String alertingConfigStr; + try (StringWriter stringWriter = new StringWriter(); + JsonWriter writer = JsonProviders.createWriter(stringWriter)) { + config.toJson(writer).flush(); + alertingConfigStr = stringWriter.toString(); + } + AlertingConfig.RequestTrigger actualAlertingConfig; + try (JsonReader reader = JsonProviders.createReader(alertingConfigStr)) { + actualAlertingConfig = AlertingConfig.RequestTrigger.fromJson(reader); + } - Assertions.assertEquals(configurationStr, alertingConfigStr); + Assertions.assertEquals(expectedRequestTrigger.name, actualAlertingConfig.name); + Assertions.assertEquals(expectedRequestTrigger.type.name(), actualAlertingConfig.type.name()); + Assertions.assertEquals( + expectedRequestTrigger.filter.type.name(), actualAlertingConfig.filter.type.name()); + Assertions.assertEquals(expectedRequestTrigger.filter.value, actualAlertingConfig.filter.value); + Assertions.assertEquals( + expectedRequestTrigger.aggregation.type.name(), + actualAlertingConfig.aggregation.type.name()); + Assertions.assertEquals( + expectedRequestTrigger.threshold.type.name(), actualAlertingConfig.threshold.type.name()); + Assertions.assertEquals( + expectedRequestTrigger.threshold.value, actualAlertingConfig.threshold.value); + Assertions.assertEquals( + expectedRequestTrigger.throttling.type.name(), actualAlertingConfig.throttling.type.name()); + Assertions.assertEquals( + expectedRequestTrigger.throttling.value, actualAlertingConfig.throttling.value); + Assertions.assertEquals( + expectedRequestTrigger.profileDuration, actualAlertingConfig.profileDuration); } @TestFactory @@ -52,28 +77,15 @@ public List configExamplesCanBeParsedToAlertApiConfig() { DynamicTest.dynamicTest( file, () -> { - ObjectMapper mapper = new ObjectMapper(); - JsonNode array = - mapper - .readTree( - RequestAlertPipelineBuilderTest.class - .getClassLoader() - .getResourceAsStream(file)) - .get("preview") - .get("profiler") - .withArray("requestTriggerEndpoints"); - - array.forEach( - config -> { - try { - AlertingConfig.RequestTrigger alertingConfig = - mapper.readValue( - config.toPrettyString(), AlertingConfig.RequestTrigger.class); - Assertions.assertNotNull(alertingConfig); - } catch (JsonProcessingException e) { - Assertions.fail(e); - } - }); + try (JsonReader reader = + JsonProviders.createReader( + RequestAlertPipelineBuilderTest.class + .getClassLoader() + .getResourceAsStream(file))) { + AlertingConfig.RequestTrigger alertingConfig = + AlertingConfig.RequestTrigger.fromJson(reader); + Assertions.assertNotNull(alertingConfig); + } })) .collect(Collectors.toList()); } diff --git a/gradle/spotbugs-exclude.xml b/gradle/spotbugs-exclude.xml index 30df4669c80..ddeece1d394 100644 --- a/gradle/spotbugs-exclude.xml +++ b/gradle/spotbugs-exclude.xml @@ -60,4 +60,8 @@ + + + + diff --git a/settings.gradle.kts b/settings.gradle.kts index c98c6e61d00..696a3802a50 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -33,7 +33,6 @@ include(":agent:agent-gc-monitor:gc-monitor-core") include(":agent:agent-gc-monitor:gc-monitor-tests") include(":agent:agent-profiler:agent-diagnostics-jfr") -include(":agent:agent-profiler:agent-diagnostics-serialization") include(":agent:agent-profiler:agent-alerting-api") include(":agent:agent-profiler:agent-diagnostics-api") include(":agent:agent-profiler:agent-diagnostics")