-
Notifications
You must be signed in to change notification settings - Fork 195
/
Configuration.java
1466 lines (1285 loc) · 57.5 KB
/
Configuration.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
package com.microsoft.applicationinsights.agent.internal.configuration;
import static java.util.Arrays.asList;
import static java.util.concurrent.TimeUnit.DAYS;
import static java.util.concurrent.TimeUnit.MINUTES;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.microsoft.applicationinsights.agent.bootstrap.diagnostics.DiagnosticsHelper;
import com.microsoft.applicationinsights.agent.bootstrap.diagnostics.status.StatusFile;
import com.microsoft.applicationinsights.agent.internal.common.FriendlyException;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.sdk.logs.data.Severity;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import javax.annotation.Nullable;
// an assumption is made throughout this file that user will not explicitly use `null` value in json
// file
// TODO how to pre-process or generally be robust in the face of explicit `null` value usage?
public class Configuration {
public String connectionString;
public Role role = new Role();
public Map<String, String> customDimensions = new HashMap<>();
public Sampling sampling = new Sampling();
public List<JmxMetric> jmxMetrics = new ArrayList<>();
public Instrumentation instrumentation = new Instrumentation();
public Heartbeat heartbeat = new Heartbeat();
public Proxy proxy = new Proxy();
public SelfDiagnostics selfDiagnostics = new SelfDiagnostics();
public PreviewConfiguration preview = new PreviewConfiguration();
public InternalConfiguration internal = new InternalConfiguration();
// this is just here to detect if using old format in order to give a helpful error message
public Map<String, Object> instrumentationSettings;
private static boolean isEmpty(@Nullable String str) {
return str == null || str.trim().isEmpty();
}
public void validate() {
instrumentation.logging.getSeverity();
preview.validate();
}
@Deprecated
public enum SpanKind {
@JsonProperty("server")
SERVER(io.opentelemetry.api.trace.SpanKind.SERVER),
@JsonProperty("client")
CLIENT(io.opentelemetry.api.trace.SpanKind.CLIENT),
@JsonProperty("consumer")
CONSUMER(io.opentelemetry.api.trace.SpanKind.CONSUMER),
@JsonProperty("producer")
PRODUCER(io.opentelemetry.api.trace.SpanKind.PRODUCER),
@JsonProperty("internal")
INTERNAL(io.opentelemetry.api.trace.SpanKind.INTERNAL);
public final io.opentelemetry.api.trace.SpanKind otelSpanKind;
SpanKind(io.opentelemetry.api.trace.SpanKind otelSpanKind) {
this.otelSpanKind = otelSpanKind;
}
}
public enum SamplingTelemetryType {
// restricted to telemetry types that are supported by SamplingOverrides
@JsonProperty("request")
REQUEST,
@JsonProperty("dependency")
DEPENDENCY,
@JsonProperty("trace")
TRACE,
@JsonProperty("exception")
EXCEPTION
}
public enum MatchType {
@JsonProperty("strict")
STRICT,
@JsonProperty("regexp")
REGEXP
}
public enum ProcessorActionType {
@JsonProperty("insert")
INSERT,
@JsonProperty("update")
UPDATE,
@JsonProperty("delete")
DELETE,
@JsonProperty("hash")
HASH,
@JsonProperty("extract")
EXTRACT,
@JsonProperty("mask")
MASK
}
public enum ProcessorType {
@JsonProperty("attribute")
ATTRIBUTE("an attribute"),
@JsonProperty("log")
LOG("a log"),
@JsonProperty("span")
SPAN("a span"),
@JsonProperty("metric-filter")
METRIC_FILTER("a metric-filter");
private final String anX;
ProcessorType(String anX) {
this.anX = anX;
}
}
private enum IncludeExclude {
INCLUDE,
EXCLUDE;
@Override
public String toString() {
return name().toLowerCase(Locale.ROOT);
}
}
public static class Role {
public String name;
public String instance;
}
public static class Sampling {
// fixed percentage of requests
@Nullable public Double percentage;
// default is 5 requests per second (set in ConfigurationBuilder if neither percentage nor
// requestsPerSecond was configured)
@Nullable public Double requestsPerSecond;
// this config option only existed in one BETA release (3.4.0-BETA)
@Deprecated @Nullable public Double limitPerSecond;
}
public static class SamplingPreview {
// this is not the default for now at least, because
//
// parent not-sampled -> child not-sampled (always, to avoid broken traces)
// parent sampled -> child will still sample at its desired rate
// note: this is just sample rate of child, not sample rate of parent times
// sample rate of child, as both are using the same trace-id hash
//
// ??? if child sample rate is higher than the parent sample rate
// parent sampled --> child sampled
// parent not-sampled --> child not-sampled
// which means that child has same effective sample rate as parent, and so its item count
// will be wrong
//
// AND SO: if want to use parent-based sampler, then need to propagate the sample rate,
// otherwise can end up with incorrect math
//
// Another (lesser) reason is because .NET SDK always propagates trace flags "00" (not
// sampled)
//
// future goal: make parentBased sampling the default if item count is received via tracestate
//
// IMPORTANT if changing this default, we need to keep it at least on Azure Functions
public boolean parentBased;
public List<SamplingOverride> overrides = new ArrayList<>();
}
public static class JmxMetric {
public String name;
public String objectName;
public String attribute;
}
public static class Instrumentation {
public EnabledByDefaultInstrumentation azureSdk = new EnabledByDefaultInstrumentation();
public EnabledByDefaultInstrumentation cassandra = new EnabledByDefaultInstrumentation();
public DatabaseInstrumentationWithMasking jdbc = new DatabaseInstrumentationWithMasking();
public EnabledByDefaultInstrumentation jms = new EnabledByDefaultInstrumentation();
public EnabledByDefaultInstrumentation kafka = new EnabledByDefaultInstrumentation();
public LoggingInstrumentation logging = new LoggingInstrumentation();
public MicrometerInstrumentation micrometer = new MicrometerInstrumentation();
public DatabaseInstrumentationWithMasking mongo = new DatabaseInstrumentationWithMasking();
public EnabledByDefaultInstrumentation quartz = new EnabledByDefaultInstrumentation();
public EnabledByDefaultInstrumentation rabbitmq = new EnabledByDefaultInstrumentation();
public EnabledByDefaultInstrumentation redis = new EnabledByDefaultInstrumentation();
public EnabledByDefaultInstrumentation springScheduling = new EnabledByDefaultInstrumentation();
}
public static class DatabaseInstrumentationWithMasking {
public boolean enabled = true;
public DatabaseMaskingConfiguration masking = new DatabaseMaskingConfiguration();
}
public static class DatabaseMaskingConfiguration {
public boolean enabled = true;
}
public static class LoggingInstrumentation {
public String level = "INFO";
public Severity getSeverity() {
return getSeverity(level);
}
public static Severity getSeverity(String level) {
switch (level.toUpperCase()) {
case "OFF":
return Severity.UNDEFINED_SEVERITY_NUMBER;
case "FATAL":
case "ERROR":
case "SEVERE":
return Severity.ERROR;
case "WARN":
case "WARNING":
return Severity.WARN;
case "INFO":
return Severity.INFO;
case "CONFIG":
case "DEBUG":
case "FINE":
case "FINER":
return Severity.DEBUG;
case "TRACE":
case "FINEST":
case "ALL":
return Severity.TRACE;
default:
throw new FriendlyException(
"Invalid logging instrumentation level: " + level, "Please provide a valid level.");
}
}
}
public static class MicrometerInstrumentation {
public boolean enabled = true;
// this is just here to detect if using this old undocumented setting in order to give a helpful
// error message
@Deprecated public int reportingIntervalSeconds = 60;
}
public static class Heartbeat {
public long intervalSeconds = MINUTES.toSeconds(15);
}
public static class Statsbeat {
// disabledAll is used internally as an emergency kill-switch to turn off Statsbeat completely
// when something goes wrong.
public boolean disabledAll = false;
public String instrumentationKey;
public String endpoint;
public long shortIntervalSeconds = MINUTES.toSeconds(15); // default to 15 minutes
public long longIntervalSeconds = DAYS.toSeconds(1); // default to daily
}
public static class PreAggregatedStandardMetricsConfiguration {
public boolean enabled = true; // pre-aggregated standard metrics are on by default
}
public static class Proxy {
public String host;
public int port = 80;
// password in json file is not secure, use APPLICATIONINSIGHTS_PROXY
public String username;
public String password;
}
public static class PreviewConfiguration {
public SamplingPreview sampling = new SamplingPreview();
public List<ProcessorConfig> processors = new ArrayList<>();
// this is just here to detect if using this old setting in order to give a helpful message
@Deprecated public boolean openTelemetryApiSupport;
public PreviewInstrumentation instrumentation = new PreviewInstrumentation();
// applies to perf counters, default custom metrics, jmx metrics, and micrometer metrics
// not sure if we'll be able to have different metric intervals in future OpenTelemetry metrics
// world,
// so safer to only allow single interval for now
public int metricIntervalSeconds = 60;
// this is just here to detect if using this old setting in order to give a helpful message
@Deprecated public Boolean ignoreRemoteParentNotSampled;
public boolean captureControllerSpans;
// this is just here to detect if using this old setting in order to give a helpful message
@Deprecated public boolean httpMethodInOperationName;
public LiveMetrics liveMetrics = new LiveMetrics();
public LegacyRequestIdPropagation legacyRequestIdPropagation = new LegacyRequestIdPropagation();
// this is needed to unblock customer, but is not the ideal long-term solution
// https://portal.microsofticm.com/imp/v3/incidents/details/266992200/home
public boolean disablePropagation;
public boolean captureHttpServer4xxAsError = true;
// LoggingLevel is no longer sent by default since 3.3.0, since the data is already available
// under SeverityLevel. This configuration is provided as a temporary measure for customers
// who are unable to update their alerts/dashboards at the same time that they are updating
// their Javaagent version
// Note: this configuration option will be removed in 4.0.0
public boolean captureLoggingLevelAsCustomDimension;
public boolean captureLogbackCodeAttributes;
// this is to support interoperability with other systems
// intentionally not allowing the removal of w3c propagator since that is key to many Azure
// integrated experiences
public List<String> additionalPropagators = new ArrayList<>();
public List<InheritedAttribute> inheritedAttributes = new ArrayList<>();
public HttpHeadersConfiguration captureHttpServerHeaders = new HttpHeadersConfiguration();
public HttpHeadersConfiguration captureHttpClientHeaders = new HttpHeadersConfiguration();
public ProfilerConfiguration profiler = new ProfilerConfiguration();
public GcEventConfiguration gcEvents = new GcEventConfiguration();
public AadAuthentication authentication = new AadAuthentication();
public PreviewStatsbeat statsbeat = new PreviewStatsbeat();
public List<ConnectionStringOverride> connectionStringOverrides = new ArrayList<>();
public List<RoleNameOverride> roleNameOverrides = new ArrayList<>();
@Deprecated
public List<InstrumentationKeyOverride> instrumentationKeyOverrides = new ArrayList<>();
public int generalExportQueueCapacity = 2048;
// metrics get flooded every 60 seconds by default, so need larger queue size to avoid dropping
// telemetry (they are much smaller so a larger queue size is ok)
public int metricsExportQueueCapacity = 65536;
// disk persistence has a default capacity of 50MB
public int diskPersistenceMaxSizeMb = 50;
// unfortunately the Java SDK behavior has always been to report the "% Processor Time" number
// as "normalized" (divided by # of CPU cores), even though it should be non-normalized
// we cannot change this existing behavior as it would break existing customers' alerts, but at
// least this configuration gives users a way to opt in to the correct behavior
//
// note: the normalized value is now separately reported under a different metric
// "% Processor Time Normalized"
public boolean useNormalizedValueForNonNormalizedCpuPercentage = true;
public List<CustomInstrumentation> customInstrumentation = new ArrayList<>();
private static final Set<String> VALID_ADDITIONAL_PROPAGATORS =
new HashSet<>(asList("b3", "b3multi"));
public void validate() {
for (SamplingOverride samplingOverride : sampling.overrides) {
samplingOverride.validate();
}
for (Configuration.ConnectionStringOverride connectionStringOverride :
connectionStringOverrides) {
connectionStringOverride.validate();
}
for (Configuration.RoleNameOverride roleNameOverride : roleNameOverrides) {
roleNameOverride.validate();
}
for (Configuration.InstrumentationKeyOverride instrumentationKeyOverride :
instrumentationKeyOverrides) {
instrumentationKeyOverride.validate();
}
for (ProcessorConfig processorConfig : processors) {
processorConfig.validate();
}
authentication.validate();
for (String additionalPropagator : additionalPropagators) {
if (!VALID_ADDITIONAL_PROPAGATORS.contains(additionalPropagator)) {
throw new FriendlyException(
"The \"additionalPropagators\" configuration contains an invalid entry: "
+ additionalPropagator,
"Please provide only valid values for \"additionalPropagators\" configuration.");
}
}
}
}
public static class InheritedAttribute {
public String key;
public AttributeType type;
public AttributeKey<?> getAttributeKey() {
switch (type) {
case STRING:
return AttributeKey.stringKey(key);
case BOOLEAN:
return AttributeKey.booleanKey(key);
case LONG:
return AttributeKey.longKey(key);
case DOUBLE:
return AttributeKey.doubleKey(key);
case STRING_ARRAY:
return AttributeKey.stringArrayKey(key);
case BOOLEAN_ARRAY:
return AttributeKey.booleanArrayKey(key);
case LONG_ARRAY:
return AttributeKey.longArrayKey(key);
case DOUBLE_ARRAY:
return AttributeKey.doubleArrayKey(key);
}
throw new IllegalStateException("Unexpected attribute key type: " + type);
}
}
public static class HttpHeadersConfiguration {
public List<String> requestHeaders = new ArrayList<>();
public List<String> responseHeaders = new ArrayList<>();
}
public enum AttributeType {
@JsonProperty("string")
STRING,
@JsonProperty("boolean")
BOOLEAN,
@JsonProperty("long")
LONG,
@JsonProperty("double")
DOUBLE,
@JsonProperty("string-array")
STRING_ARRAY,
@JsonProperty("boolean-array")
BOOLEAN_ARRAY,
@JsonProperty("long-array")
LONG_ARRAY,
@JsonProperty("double-array")
DOUBLE_ARRAY
}
public static class LegacyRequestIdPropagation {
public boolean enabled;
}
public static class InternalConfiguration {
// This is used for collecting internal stats
public Statsbeat statsbeat = new Statsbeat();
public PreAggregatedStandardMetricsConfiguration preAggregatedStandardMetrics =
new PreAggregatedStandardMetricsConfiguration();
}
public static class PreviewInstrumentation {
public DisabledByDefaultInstrumentation play = new DisabledByDefaultInstrumentation();
public DisabledByDefaultInstrumentation akka = new DisabledByDefaultInstrumentation();
public DisabledByDefaultInstrumentation apacheCamel = new DisabledByDefaultInstrumentation();
// this is just here to detect if using this old setting in order to give a helpful message
@Deprecated
public DisabledByDefaultInstrumentation azureSdk = new DisabledByDefaultInstrumentation();
public DisabledByDefaultInstrumentation grizzly = new DisabledByDefaultInstrumentation();
// this is just here to detect if using this old setting in order to give a helpful message
@Deprecated
public DisabledByDefaultInstrumentation javaHttpClient = new DisabledByDefaultInstrumentation();
// this is just here to detect if using this old setting in order to give a helpful message
@Deprecated
public DisabledByDefaultInstrumentation jaxws = new DisabledByDefaultInstrumentation();
// this is just here to detect if using this old setting in order to give a helpful message
@Deprecated
public DisabledByDefaultInstrumentation quartz = new DisabledByDefaultInstrumentation();
// this is just here to detect if using this old setting in order to give a helpful message
@Deprecated
public DisabledByDefaultInstrumentation rabbitmq = new DisabledByDefaultInstrumentation();
public DisabledByDefaultInstrumentation springIntegration =
new DisabledByDefaultInstrumentation();
public DisabledByDefaultInstrumentation vertx = new DisabledByDefaultInstrumentation();
// this is opt-in because it can cause startup slowness due to expensive matchers
public DisabledByDefaultInstrumentation jaxrsAnnotations =
new DisabledByDefaultInstrumentation();
}
public static class PreviewStatsbeat {
// disabled is used by customer to turn off non-essential Statsbeat, e.g. disk persistence
// operation status, optional network statsbeat, other endpoints except Breeze, etc.
public boolean disabled = false;
}
public static class ConnectionStringOverride {
public String httpPathPrefix;
public String connectionString;
public void validate() {
if (httpPathPrefix == null) {
// TODO add doc and go link, similar to telemetry processors
throw new FriendlyException(
"A connection string override configuration is missing an \"httpPathPrefix\".",
"Please provide an \"httpPathPrefix\" for the connection string override configuration.");
}
if (connectionString == null) {
// TODO add doc and go link, similar to telemetry processors
throw new FriendlyException(
"A connection string override configuration is missing an \"connectionString\".",
"Please provide an \"instrumentationKey\" for the connection string override configuration.");
}
}
}
public static class RoleNameOverride {
public String httpPathPrefix;
public String roleName;
public void validate() {
if (httpPathPrefix == null) {
// TODO add doc and go link, similar to telemetry processors
throw new FriendlyException(
"A role name override configuration is missing an \"httpPathPrefix\".",
"Please provide an \"httpPathPrefix\" for the role name override configuration.");
}
if (roleName == null) {
// TODO add doc and go link, similar to telemetry processors
throw new FriendlyException(
"An role name override configuration is missing a \"roleName\".",
"Please provide a \"roleName\" for the role name override configuration.");
}
}
}
@Deprecated
public static class InstrumentationKeyOverride {
public String httpPathPrefix;
public String instrumentationKey;
public void validate() {
if (httpPathPrefix == null) {
// TODO add doc and go link, similar to telemetry processors
throw new FriendlyException(
"An instrumentation key override configuration is missing an \"httpPathPrefix\".",
"Please provide an \"httpPathPrefix\" for the instrumentation key override configuration.");
}
if (instrumentationKey == null) {
// TODO add doc and go link, similar to telemetry processors
throw new FriendlyException(
"An instrumentation key override configuration is missing an \"instrumentationKey\".",
"Please provide an \"instrumentationKey\" for the instrumentation key override configuration.");
}
}
}
public static class CustomInstrumentation {
public String className;
public String methodName;
}
public static class EnabledByDefaultInstrumentation {
public boolean enabled = true;
}
public static class DisabledByDefaultInstrumentation {
public boolean enabled;
}
public static class LiveMetrics {
public boolean enabled = true;
}
public static class SelfDiagnostics {
public String level = "info";
public String destination = "file+console";
public DestinationFile file = new DestinationFile();
}
public static class DestinationFile {
private static final String DEFAULT_NAME = "applicationinsights.log";
public String path = getDefaultPath();
public int maxSizeMb = 5;
public int maxHistory = 1;
private static String getDefaultPath() {
if (!DiagnosticsHelper.isRpIntegration()) {
if (isRuntimeAttached()) { // With runtime attachment, the agent jar is located in a temp
// folder that is dropped when the JVM shuts down
String userDir = System.getProperty("user.dir");
return userDir + File.separator + DEFAULT_NAME;
}
return DEFAULT_NAME; // this will be relative to the directory where agent jar is located
}
if (DiagnosticsHelper.useAppSvcRpIntegrationLogging()) {
return StatusFile.getLogDir() + "/" + DEFAULT_NAME;
}
// azure functions and azure spring cloud
return DEFAULT_NAME;
}
}
private static boolean isRuntimeAttached() {
return Boolean.getBoolean("applicationinsights.internal.runtime.attached");
}
public static class SamplingOverride {
@Deprecated @Nullable public SpanKind spanKind;
// TODO (trask) make this required when moving out of preview
// for now the default is both "request" and "dependency" for backwards compatibility
@Nullable public SamplingTelemetryType telemetryType;
// this config option existed in one GA release (3.4.0), and was then replaced by telemetryType
@Deprecated @Nullable public SamplingTelemetryType telemetryKind;
// this config option only existed in one BETA release (3.4.0-BETA)
@Deprecated @Nullable public Boolean includingStandaloneTelemetry;
// not using include/exclude, because you can still get exclude with this by adding a second
// (exclude) override above it
// (since only the first matching override is used)
public List<SamplingOverrideAttribute> attributes = new ArrayList<>();
public Double percentage;
public String id; // optional, used for debugging purposes only
public boolean isForRequestTelemetry() {
return telemetryType == SamplingTelemetryType.REQUEST
// this part is for backwards compatibility:
|| (telemetryType == null && spanKind != SpanKind.CLIENT);
}
public boolean isForDependencyTelemetry() {
return telemetryType == SamplingTelemetryType.DEPENDENCY
// this part is for backwards compatibility:
|| (telemetryType == null && spanKind != SpanKind.SERVER);
}
public void validate() {
if (percentage == null) {
// TODO add doc and go link, similar to telemetry processors
throw new FriendlyException(
"A sampling override configuration is missing a \"percentage\".",
"Please provide a \"percentage\" for the sampling override configuration.");
}
if (percentage < 0 || percentage > 100) {
// TODO add doc and go link, similar to telemetry processors
throw new FriendlyException(
"A sampling override configuration has a \"percentage\" that is not between 0 and 100.",
"Please provide a \"percentage\" that is between 0 and 100 for the sampling override configuration.");
}
for (SamplingOverrideAttribute attribute : attributes) {
attribute.validate();
}
}
}
public static class SamplingOverrideAttribute {
public String key;
@Nullable public String value;
@Nullable public MatchType matchType;
private void validate() {
if (isEmpty(key)) {
// TODO add doc and go link, similar to telemetry processors
throw new FriendlyException(
"A sampling override configuration has an attribute section that is missing a \"key\".",
"Please provide a \"key\" under the attribute section of the sampling override configuration.");
}
if (matchType == null && value != null) {
throw new FriendlyException(
"A sampling override configuration has an attribute section with a \"value\" that is missing a \"matchType\".",
"Please provide a \"matchType\" under the attribute section of the sampling override configuration.");
}
if (matchType == MatchType.REGEXP) {
if (isEmpty(value)) {
// TODO add doc and go link, similar to telemetry processors
throw new FriendlyException(
"Asampling override configuration has an attribute with matchType regexp that is missing a \"value\".",
"Please provide a key under the attribute section of the sampling override configuration.");
}
validateRegex(value);
}
}
private static void validateRegex(String value) {
try {
Pattern.compile(value);
} catch (PatternSyntaxException e) {
// TODO add doc and go link, similar to telemetry processors
throw new FriendlyException(
"A telemetry filter configuration has an invalid regex: " + value,
"Please provide a valid regex in the telemetry filter configuration.",
e);
}
}
}
public static class ProcessorConfig {
public ProcessorType type;
public ProcessorIncludeExclude include;
public ProcessorIncludeExclude exclude;
public List<ProcessorAction> actions =
new ArrayList<>(); // specific for processor type "attributes"
public NameConfig name; // specific for processor type "span"
public NameConfig body; // specific for processor types "log"
public String id; // optional, used for debugging purposes only
public void validate() {
if (type == null) {
throw new FriendlyException(
"A telemetry processor configuration is missing a \"type\".",
"Please provide a \"type\" in the telemetry processor configuration. "
+ "Learn more about telemetry processors here: https://go.microsoft.com/fwlink/?linkid=2151557");
}
if (include != null) {
include.validate(type, IncludeExclude.INCLUDE);
}
if (exclude != null) {
exclude.validate(type, IncludeExclude.EXCLUDE);
}
switch (type) {
case ATTRIBUTE:
validateAttributeProcessorConfig();
return;
case SPAN:
validateSpanProcessorConfig();
return;
case LOG:
validateLogProcessorConfig();
return;
case METRIC_FILTER:
validateMetricFilterProcessorConfig();
return;
}
throw new AssertionError("Unexpected processor type: " + type);
}
public void validateAttributeProcessorConfig() {
if (actions.isEmpty()) {
throw new FriendlyException(
"An attribute processor configuration has no actions.",
"Please provide at least one action in the attribute processor configuration. "
+ "Learn more about attribute processors here: https://go.microsoft.com/fwlink/?linkid=2151557");
}
for (ProcessorAction action : actions) {
action.validate();
}
validateSectionIsNull(name, "name");
validateSectionIsNull(body, "body");
}
public void validateSpanProcessorConfig() {
if (name == null) {
throw new FriendlyException(
"a span processor configuration is missing a \"name\" section.",
"Please provide a \"name\" section in the span processor configuration. "
+ "Learn more about span processors here: https://go.microsoft.com/fwlink/?linkid=2151557");
}
name.validate(type);
validateActionsIsEmpty();
validateSectionIsNull(body, "body");
}
public void validateLogProcessorConfig() {
if (body == null) {
throw new FriendlyException(
"a log processor configuration is missing a \"body\" section.",
"Please provide a \"body\" section in the log processor configuration. "
+ "Learn more about log processors here: https://go.microsoft.com/fwlink/?linkid=2151557");
}
body.validate(type);
validateActionsIsEmpty();
validateSectionIsNull(name, "name");
}
public void validateMetricFilterProcessorConfig() {
if (exclude == null) {
throw new FriendlyException(
"a metric-filter processor configuration is missing an \"exclude\" section.",
"Please provide a \"exclude\" section in the metric-filter processor configuration. "
+ "Learn more about metric-filter processors here: https://go.microsoft.com/fwlink/?linkid=2151557");
}
validateActionsIsEmpty();
validateSectionIsNull(name, "name");
validateSectionIsNull(body, "body");
}
private void validateActionsIsEmpty() {
if (!actions.isEmpty()) {
throwUnexpectedSectionFriendlyException("actions");
}
}
private void validateSectionIsNull(@Nullable Object section, String sectionName) {
if (section != null) {
throwUnexpectedSectionFriendlyException(sectionName);
}
}
private void throwUnexpectedSectionFriendlyException(String sectionName) {
throw new FriendlyException(
type.anX + " processor configuration has an unexpected section \"" + sectionName + "\".",
"Please do not provide a \""
+ sectionName
+ "\" section in the "
+ type
+ " processor configuration. "
+ "Learn more about "
+ type
+ " processors here: https://go.microsoft.com/fwlink/?linkid=2151557");
}
}
public static class NameConfig {
public List<String> fromAttributes = new ArrayList<>();
public ToAttributeConfig toAttributes;
public String separator;
public void validate(ProcessorType processorType) {
if (fromAttributes.isEmpty() && toAttributes == null) {
// TODO different links for different processor types?
throw new FriendlyException(
processorType.anX
+ " processor configuration has \"name\" action with no \"fromAttributes\" and no \"toAttributes\".",
"Please provide at least one of \"fromAttributes\" or \"toAttributes\" under the name section of the "
+ processorType
+ " processor configuration. "
+ "Learn more about "
+ processorType
+ " processors here: https://go.microsoft.com/fwlink/?linkid=2151557");
}
if (toAttributes != null) {
toAttributes.validate(processorType);
}
}
}
public static class ToAttributeConfig {
public List<String> rules = new ArrayList<>();
public void validate(ProcessorType processorType) {
if (rules.isEmpty()) {
throw new FriendlyException(
processorType.anX
+ " processor configuration has \"toAttributes\" section with no \"rules\".",
"Please provide at least one rule under the \"toAttributes\" section of the "
+ processorType
+ " processor configuration. "
+ "Learn more about "
+ processorType
+ " processors here: https://go.microsoft.com/fwlink/?linkid=2151557");
}
for (String rule : rules) {
validateRegex(rule, processorType);
}
}
}
public static class ProcessorIncludeExclude {
public MatchType matchType;
public List<String> spanNames = new ArrayList<>();
public List<String> logBodies = new ArrayList<>();
public List<String> metricNames = new ArrayList<>();
public List<ProcessorAttribute> attributes = new ArrayList<>();
public void validate(ProcessorType processorType, IncludeExclude includeExclude) {
if (matchType == null) {
throw new FriendlyException(
processorType.anX
+ " processor configuration has an "
+ includeExclude
+ " section that is missing a \"matchType\".",
"Please provide a \"matchType\" under the "
+ includeExclude
+ " section of the "
+ processorType
+ " processor configuration. "
+ "Learn more about "
+ processorType
+ " processors here: https://go.microsoft.com/fwlink/?linkid=2151557");
}
for (ProcessorAttribute attribute : attributes) {
if (isEmpty(attribute.key)) {
throw new FriendlyException(
processorType.anX
+ " processor configuration has an "
+ includeExclude
+ " section that is missing a \"key\".",
"Please provide a \"key\" under the "
+ includeExclude
+ " section of the "
+ processorType
+ " processor configuration. "
+ "Learn more about "
+ processorType
+ " processors here: https://go.microsoft.com/fwlink/?linkid=2151557");
}
if (matchType == MatchType.REGEXP && attribute.value != null) {
validateRegex(attribute.value, processorType);
}
}
switch (processorType) {
case ATTRIBUTE:
validAttributeProcessorIncludeExclude(includeExclude);
return;
case LOG:
validateLogProcessorIncludeExclude(includeExclude);
return;
case SPAN:
validateSpanProcessorIncludeExclude(includeExclude);
return;
case METRIC_FILTER:
validateMetricFilterProcessorExclude(includeExclude);
return;
}
throw new IllegalStateException("Unexpected processor type: " + processorType);
}
private void validAttributeProcessorIncludeExclude(IncludeExclude includeExclude) {
if (attributes.isEmpty() && spanNames.isEmpty() && logBodies.isEmpty()) {
throw new FriendlyException(
"An attribute processor configuration has an "
+ includeExclude
+ " section with no \"spanNames\" and no \"attributes\" and no \"logBodies\".",
"Please provide at least one of \"spanNames\" or \"attributes\" or \"logBodies\" under the "
+ includeExclude
+ " section of the attribute processor configuration. "
+ "Learn more about attribute processors here: https://go.microsoft.com/fwlink/?linkid=2151557");
}
if (matchType == MatchType.REGEXP) {
for (String spanName : spanNames) {
validateRegex(spanName, ProcessorType.ATTRIBUTE);
}
for (String logBody : logBodies) {
validateRegex(logBody, ProcessorType.ATTRIBUTE);
}
}
validateSectionIsEmpty(metricNames, ProcessorType.ATTRIBUTE, includeExclude, "metricNames");
}
private void validateLogProcessorIncludeExclude(IncludeExclude includeExclude) {
if (logBodies.isEmpty() && attributes.isEmpty()) {
throw new FriendlyException(
"A log processor configuration has an "
+ includeExclude
+ " section with no \"attributes\" and no \"logBodies\".",
"Please provide \"attributes\" or \"logBodies\" under the "
+ includeExclude
+ " section of the log processor configuration. "
+ "Learn more about log processors here: https://go.microsoft.com/fwlink/?linkid=2151557");
}
if (matchType == MatchType.REGEXP) {
for (String logBody : logBodies) {
validateRegex(logBody, ProcessorType.LOG);
}
}
validateSectionIsEmpty(spanNames, ProcessorType.LOG, includeExclude, "spanNames");
validateSectionIsEmpty(metricNames, ProcessorType.LOG, includeExclude, "metricNames");
}
private void validateSpanProcessorIncludeExclude(IncludeExclude includeExclude) {
if (spanNames.isEmpty() && attributes.isEmpty()) {
throw new FriendlyException(
"A span processor configuration has "
+ includeExclude
+ " section with no \"spanNames\" and no \"attributes\".",
"Please provide at least one of \"spanNames\" or \"attributes\" under the "
+ includeExclude
+ " section of the span processor configuration. "
+ "Learn more about span processors here: https://go.microsoft.com/fwlink/?linkid=2151557");
}
if (matchType == MatchType.REGEXP) {
for (String spanName : spanNames) {
validateRegex(spanName, ProcessorType.SPAN);
}
}