From a494d5a7aba9ae1f587615212943828a57201637 Mon Sep 17 00:00:00 2001 From: Hugh Simpson Date: Sat, 2 Mar 2024 15:35:30 +0000 Subject: [PATCH 1/5] initial prep for scalafmt --- .git-blame-ignore-revs | 0 .scalafmt.conf | 20 ++++++++++++++++++++ project/plugins.sbt | 1 + 3 files changed, 21 insertions(+) create mode 100644 .git-blame-ignore-revs create mode 100644 .scalafmt.conf diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 000000000..e69de29bb diff --git a/.scalafmt.conf b/.scalafmt.conf new file mode 100644 index 000000000..bdb782069 --- /dev/null +++ b/.scalafmt.conf @@ -0,0 +1,20 @@ +version = "3.8.0" + +runner.dialect = "scala213" + +maxColumn = 120 + +align.preset = some + +binPack.parentConstructors = source + +docstrings.style = keep + +indent.defnSite = 2 + +indentOperator.excludeRegex = "^.+$" +indentOperator.exemptScope = all + +newlines { + source = keep +} diff --git a/project/plugins.sbt b/project/plugins.sbt index 437e1df70..4ae8d45fc 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -12,6 +12,7 @@ addSbtPlugin("de.heikoseeberger" % "sbt-header" % "5.2.0") addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "3.9.13") addSbtPlugin("com.jsuereth" % "sbt-pgp" % "2.0.1") addSbtPlugin("de.heikoseeberger" % "sbt-header" % "5.5.0") +addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.5.2") addSbtPlugin("com.lightbend.akka.grpc" % "sbt-akka-grpc" % "2.1.3") addSbtPlugin("org.apache.pekko" % "pekko-grpc-sbt-plugin" % "1.0.0") From 022216d6b1ebe4dd0c00aef204625f7f3372fc90 Mon Sep 17 00:00:00 2001 From: Hugh Simpson Date: Sat, 2 Mar 2024 15:35:55 +0000 Subject: [PATCH 2/5] reformat --- .../main/scala/kamon/runtime/Attacher.scala | 12 +- .../kamon/bench/TagSetCreationBenchmark.scala | 20 +- .../kamon/bench/TagSetLookupBenchmark.scala | 1 - .../bench/ThreadLocalStorageBenchmark.scala | 5 +- .../kamon/InitialConfigLoadingSpec.scala | 7 +- .../test/scala/kamon/KamonLifecycleSpec.scala | 3 +- .../test/scala/kamon/UtilsOnConfigSpec.scala | 10 +- .../kamon/context/BinaryPropagationSpec.scala | 28 +- .../kamon/context/HttpPropagationSpec.scala | 45 +-- .../context/ThreadLocalStorageSpec.scala | 3 +- .../test/scala/kamon/metric/CounterSpec.scala | 6 +- .../test/scala/kamon/metric/GaugeSpec.scala | 55 ++-- .../scala/kamon/metric/HistogramSpec.scala | 40 +-- .../kamon/metric/InstrumentGroupSpec.scala | 21 +- .../scala/kamon/metric/MetricLookupSpec.scala | 13 +- .../PeriodSnapshotAccumulatorSpec.scala | 119 +++++--- .../scala/kamon/metric/RangeSamplerSpec.scala | 4 +- .../test/scala/kamon/metric/TimerSpec.scala | 4 +- .../kamon/module/ModuleRegistrySpec.scala | 15 +- .../scala/kamon/status/EnvironmentSpec.scala | 8 +- .../src/test/scala/kamon/tag/TagSetSpec.scala | 17 +- .../trace/B3SingleSpanPropagationSpec.scala | 59 ++-- .../kamon/trace/B3SpanPropagationSpec.scala | 64 ++-- .../trace/DataDogSpanPropagationSpec.scala | 86 +++--- .../scala/kamon/trace/LocalSpanSpec.scala | 31 +- .../kamon/trace/LocalTailSamplerSpec.scala | 14 +- .../kamon/trace/QuickSpanCreationSpec.scala | 7 +- .../test/scala/kamon/trace/SamplerSpec.scala | 2 +- .../SingleLengthIdentifierSchemeSpec.scala | 4 +- .../scala/kamon/trace/SpanMetricsSpec.scala | 17 +- .../kamon/trace/SpanReportingDelaySpec.scala | 4 +- .../test/scala/kamon/trace/TracerSpec.scala | 23 +- .../kamon/trace/UberSpanPropagationSpec.scala | 63 ++-- .../W3CTraceContextSpanPropagationSpec.scala | 43 +-- .../src/test/scala/kamon/util/ClockSpec.scala | 35 ++- .../kamon/util/EnvironmentTagsSpec.scala | 12 +- .../ExponentiallyWeightedAverageSpec.scala | 44 +-- .../test/scala/kamon/util/FilterSpec.scala | 1 - .../src/main/scala/kamon/Configuration.scala | 15 +- .../main/scala/kamon/ContextPropagation.scala | 1 - .../src/main/scala/kamon/ContextStorage.scala | 10 +- .../src/main/scala/kamon/CurrentStatus.scala | 6 +- .../src/main/scala/kamon/Init.scala | 27 +- .../src/main/scala/kamon/Kamon.scala | 16 +- .../main/scala/kamon/ModuleManagement.scala | 8 +- .../src/main/scala/kamon/Tracing.scala | 10 - .../kamon/context/BinaryPropagation.scala | 37 +-- .../main/scala/kamon/context/Context.scala | 31 +- .../scala/kamon/context/HttpPropagation.scala | 44 +-- .../main/scala/kamon/context/Storage.scala | 10 +- .../src/main/scala/kamon/metric/Counter.scala | 23 +- .../scala/kamon/metric/Distribution.scala | 54 ++-- .../src/main/scala/kamon/metric/Gauge.scala | 21 +- .../main/scala/kamon/metric/Histogram.scala | 50 +-- .../main/scala/kamon/metric/Instrument.scala | 4 +- .../scala/kamon/metric/InstrumentGroup.scala | 34 ++- .../scala/kamon/metric/MeasurementUnit.scala | 16 +- .../src/main/scala/kamon/metric/Metric.scala | 59 ++-- .../scala/kamon/metric/MetricBuilding.scala | 54 +++- .../scala/kamon/metric/MetricFactory.scala | 209 +++++++++---- .../scala/kamon/metric/MetricRegistry.scala | 107 ++++--- .../scala/kamon/metric/MetricSnapshot.scala | 21 +- .../scala/kamon/metric/PeriodSnapshot.scala | 64 ++-- .../scala/kamon/metric/RangeSampler.scala | 19 +- .../src/main/scala/kamon/metric/Tagging.scala | 2 +- .../src/main/scala/kamon/metric/Timer.scala | 22 +- .../scala/kamon/module/MetricReporter.scala | 18 +- .../src/main/scala/kamon/module/Module.scala | 7 +- .../scala/kamon/module/ModuleRegistry.scala | 135 +++++---- .../scala/kamon/module/ScheduledAction.scala | 1 - .../src/main/scala/kamon/package.scala | 1 - .../main/scala/kamon/status/Environment.scala | 10 +- .../kamon/status/InstrumentationStatus.scala | 10 +- .../src/main/scala/kamon/status/Status.scala | 12 +- .../src/main/scala/kamon/tag/Lookups.scala | 16 +- .../src/main/scala/kamon/tag/Tag.scala | 4 - .../src/main/scala/kamon/tag/TagSet.scala | 50 ++- .../scala/kamon/trace/AdaptiveSampler.scala | 170 +++++------ .../scala/kamon/trace/ConstantSampler.scala | 4 +- .../src/main/scala/kamon/trace/Hooks.scala | 8 - .../main/scala/kamon/trace/Identifier.scala | 19 +- .../scala/kamon/trace/RandomSampler.scala | 6 +- .../src/main/scala/kamon/trace/Sampler.scala | 2 +- .../src/main/scala/kamon/trace/Span.scala | 149 +++++---- .../scala/kamon/trace/SpanPropagation.scala | 109 +++---- .../src/main/scala/kamon/trace/Trace.scala | 1 - .../src/main/scala/kamon/trace/Tracer.scala | 115 ++++--- .../util/CallingThreadExecutionContext.scala | 2 +- .../src/main/scala/kamon/util/Clock.scala | 11 +- .../main/scala/kamon/util/DynamicAccess.scala | 8 +- .../src/main/scala/kamon/util/EWMA.scala | 16 +- .../scala/kamon/util/EnvironmentTags.scala | 26 +- .../src/main/scala/kamon/util/Filter.scala | 28 +- .../src/main/scala/kamon/util/HexCodec.scala | 3 +- .../main/scala/kamon/util/UnitConverter.scala | 14 +- .../kamon/status/page/JsonMarshalling.scala | 33 +- .../scala/kamon/status/page/StatusPage.scala | 10 +- .../kamon/status/page/StatusPageServer.scala | 27 +- .../kamon/testkit/InstrumentInspection.scala | 39 +-- .../kamon/testkit/MetricInspection.scala | 48 +-- .../kamon/testkit/MetricSnapshotBuilder.scala | 24 +- .../scala/kamon/testkit/Reconfigure.scala | 9 - .../main/scala/kamon/testkit/Reflection.scala | 4 +- .../scala/kamon/testkit/SpanInspection.scala | 30 +- .../kamon/testkit/MetricInspectionSpec.scala | 6 +- .../grpc/AkkaGrpcServerInstrumentation.scala | 1 - .../akka/grpc/AkkaGrpcTracingSpec.scala | 1 - .../akka/grpc/GreeterServiceImpl.scala | 1 - .../http/AkkaHttpServerInstrumentation.scala | 50 +-- .../http/AkkaHttpClientInstrumentation.scala | 19 +- .../akka/http/AkkaHttpInstrumentation.scala | 21 +- .../akka/http/ServerFlowWrapper.scala | 285 ++++++++++-------- .../akka/http/TracingDirectives.scala | 3 +- .../akka/http/AkkaHttpClientTracingSpec.scala | 8 +- .../akka/http/AkkaHttpServerMetricsSpec.scala | 20 +- .../akka/http/AkkaHttpServerTracingSpec.scala | 18 +- .../akka/http/ServerFlowWrapperSpec.scala | 12 +- .../kamon/testkit/TestNameGenerator.scala | 2 - .../scala/kamon/testkit/TestWebServer.scala | 100 +++--- .../kamon/annotation/el/ELEvaluator.scala | 14 +- .../annotation/el/EnhancedELProcessor.scala | 21 +- .../scala/kamon/annotation/util/Hooks.scala | 9 +- .../AnnotationInstrumentationSpec.scala | 48 +-- ...ticAnnotationInstrumentationJavaSpec.scala | 33 +- .../StaticAnnotationInstrumentationSpec.scala | 35 ++- .../AwsSdkClientExecutionInterceptor.scala | 18 +- .../aws/sdk/AwsSdkRequestHandler.scala | 10 +- .../aws/sdk/DynamoDBTracingSpec.scala | 15 +- .../CaffeineCacheInstrumentation.scala | 4 +- .../caffeine/KamonStatsCounter.scala | 1 - .../caffeine/CaffeineAsyncCacheSpec.scala | 11 +- .../caffeine/CaffeineSyncCacheSpec.scala | 11 +- .../driver/core/ConnectionPoolAdvices.scala | 56 ++-- .../driver/core/ExecutionAdvices.scala | 46 +-- .../cassandra/CassandraInstrumentation.scala | 34 +-- .../cassandra/NodeConnectionPoolMetrics.scala | 36 +-- .../cassandra/SessionMetrics.scala | 38 +-- .../driver/DriverInstrumentation.scala | 17 +- .../driver/InstrumentedSession.scala | 30 +- .../executors/ExecutorInstrumentation.scala | 6 +- .../cassandra/metrics/NodeMonitor.scala | 2 +- .../cats3/IOFiberInstrumentation.scala | 32 +- .../cats3/CatsIoInstrumentationSpec.scala | 57 ++-- .../cats/CatsIOInstrumentationSpec.scala | 3 +- .../elasticsearch/ESInstrumentation.scala | 10 +- .../ElasticSearchInstrumentationTest.scala | 13 +- .../ExecutorInstrumentationBenchmark.scala | 2 +- .../kamon/instrumentation/package.scala | 2 +- .../executor/ExecutorInstrumentation.scala | 219 ++++++++++---- .../executor/ExecutorMetrics.scala | 18 +- ...reContextOnSubmitInstrumentationSpec.scala | 41 +-- .../executor/ExecutorMetricsSpec.scala | 73 ++--- .../executor/ExecutorsRegistrationSpec.scala | 13 +- .../OnSubmitContextPropagationSpec.scala | 41 +-- .../finagle/client/IdConversionOps.scala | 6 +- .../finagle/client/KamonFinagleTracer.scala | 34 +-- .../finagle/client/SpanInitializer.scala | 1 + .../finagle/client/HttpClientOpsSpec.scala | 25 +- .../src/main/scala/kamon/http4s/Http4s.scala | 2 +- .../middleware/client/KamonSupport.scala | 10 +- .../middleware/server/KamonSupport.scala | 22 +- .../src/main/scala/kamon/http4s/package.scala | 4 +- .../scala/kamon/http4s/HttpMetricsSpec.scala | 5 +- .../http4s/ServerInstrumentationSpec.scala | 2 +- .../src/main/scala/kamon/http4s/Http4s.scala | 2 +- .../middleware/client/KamonSupport.scala | 10 +- .../middleware/server/KamonSupport.scala | 22 +- .../src/main/scala/kamon/http4s/package.scala | 4 +- .../scala/kamon/http4s/HttpMetricsSpec.scala | 4 +- .../http4s/ServerInstrumentationSpec.scala | 2 +- .../scala-2.12/scala/annotation/static.scala | 2 +- .../context/CaptureCurrentContext.scala | 2 +- .../context/CaptureCurrentTimestamp.scala | 3 +- .../instrumentation/context/HasContext.scala | 6 +- .../context/HasTimestamp.scala | 3 +- .../context/InvokeWithCapturedContext.scala | 4 +- .../http/HttpClientInstrumentation.scala | 22 +- .../instrumentation/http/HttpMessage.scala | 2 +- .../http/HttpOperationNameGenerator.scala | 1 - .../http/HttpServerInstrumentation.scala | 72 +++-- .../http/HttpServerMetrics.scala | 26 +- .../HttpServerResponseHeaderGenerator.scala | 6 +- .../http/OperationNameSettings.scala | 13 +- .../scala/kamon/instrumentation/package.scala | 23 +- .../kamon/instrumentation/trace/Tagger.scala | 4 +- .../context/ContextInstrumentationSpec.scala | 1 - .../http/HttpClientInstrumentationSpec.scala | 64 ++-- .../http/HttpServerInstrumentationSpec.scala | 167 +++++++--- .../jdbc/HikariInstrumentation.scala | 46 ++- .../jdbc/JdbcInstrumentation.scala | 19 +- .../instrumentation/jdbc/JdbcMetrics.scala | 4 +- .../jdbc/StatementInstrumentation.scala | 30 +- .../jdbc/StatementMonitor.scala | 16 +- .../StatementInstrumentationAdvisors.scala | 9 +- .../internal/PoolEntryProtectedAccess.scala | 2 +- .../jdbc/utils/SqlVisitor.scala | 44 ++- .../jdbc/HikariInstrumentationSpec.scala | 38 +-- .../jdbc/SlickInstrumentationSpec.scala | 3 +- .../jdbc/StatementInstrumentationSpec.scala | 47 +-- .../client/ConsumerInstrumentation.scala | 2 +- .../client/ContextSerializationHelper.scala | 2 +- .../kafka/client/KafkaInstrumentation.scala | 17 +- .../client/ProducerInstrumentation.scala | 7 +- .../kafka/client/RecordProcessor.scala | 15 +- ...fkaClientsTracingInstrumentationSpec.scala | 42 ++- .../CustomPropagationImplementation.scala | 13 +- .../kafka/testutil/DotFileGenerator.scala | 36 ++- .../testutil/SpanReportingTestScope.scala | 8 +- .../CircuitBreakerMetricsProviderImpl.scala | 2 +- .../instrumentation/lagom/LagomMetrics.scala | 12 +- .../logback/LogbackInstrumentation.scala | 8 +- .../logback/LogbackMetrics.scala | 2 +- .../logback/tools/ContextEntryConverter.scala | 6 +- .../logback/tools/ContextTagConverter.scala | 6 +- .../tools/EntriesCounterAppender.scala | 16 +- .../logback/tools/SpanIDConverter.scala | 2 +- .../tools/SpanOperationNameConverter.scala | 2 +- .../logback/tools/TraceIDConverter.scala | 2 +- .../LogbackEntriesCounterAppenderSpec.scala | 3 +- .../logback/LogbackMdcCopyingSpec.scala | 24 +- .../instrumentation/logback/package.scala | 18 +- .../mongo/MongoClientInstrumentation.scala | 3 +- .../mongo/EmbeddedMongoTest.scala | 1 - .../MongoScalaDriverInstrumentationSpec.scala | 12 +- .../MongoSyncDriverInstrumentationSpec.scala | 25 +- .../mongo/MongoClientInstrumentation.scala | 3 +- .../mongo/EmbeddedMongoTest.scala | 1 - .../MongoScalaDriverInstrumentationSpec.scala | 12 +- .../MongoSyncDriverInstrumentationSpec.scala | 25 +- .../instrumentation/KamonOkHttpTracing.scala | 52 ++-- .../OkHttpTracingInstrumentationSpec.scala | 21 +- .../opensearch/OSInstrumentation.scala | 5 +- .../OpenSearchInstrumentationTest.scala | 13 +- .../grpc/PekkoGrpcServerInstrumentation.scala | 1 - .../pekko/grpc/GreeterServiceImpl.scala | 1 - .../pekko/grpc/PekkoGrpcTracingSpec.scala | 1 - .../http/PekkoHttpClientInstrumentation.scala | 19 +- .../pekko/http/PekkoHttpInstrumentation.scala | 21 +- .../http/PekkoHttpServerInstrumentation.scala | 36 ++- .../pekko/http/ServerFlowWrapper.scala | 285 ++++++++++-------- .../pekko/http/TracingDirectives.scala | 3 +- .../http/PekkoHttpClientTracingSpec.scala | 8 +- .../http/PekkoHttpServerMetricsSpec.scala | 20 +- .../http/PekkoHttpServerTracingSpec.scala | 18 +- .../pekko/http/ServerFlowWrapperSpec.scala | 12 +- .../kamon/testkit/TestNameGenerator.scala | 2 - .../scala/kamon/testkit/TestWebServer.scala | 100 +++--- .../pekko/PekkoClusterShardingMetrics.scala | 76 +++-- .../pekko/PekkoInstrumentation.scala | 12 +- .../instrumentation/pekko/PekkoMetrics.scala | 71 +++-- .../pekko/PekkoRemoteInstrumentation.scala | 1 - .../pekko/PekkoRemoteMetrics.scala | 8 +- .../instrumentations/ActorCellInfo.scala | 44 ++- .../ActorInstrumentation.scala | 22 +- .../ActorLoggingInstrumentation.scala | 2 +- .../pekko/instrumentations/ActorMonitor.scala | 135 ++++++--- .../ActorMonitorInstrumentation.scala | 16 +- .../ActorRefInstrumentation.scala | 2 - .../AskPatternInstrumentation.scala | 20 +- .../ClusterInstrumentation.scala | 51 ++-- .../instrumentations/DispatcherInfo.scala | 2 +- .../DispatcherInstrumentation.scala | 114 ++++--- .../EnvelopeInstrumentation.scala | 2 - .../EventStreamInstrumentation.scala | 10 +- .../RouterInstrumentation.scala | 9 +- .../SystemMessageInstrumentation.scala | 2 +- .../internal/CellWrapper.scala | 18 +- .../remote/MessageBufferInstrumentation.scala | 1 - .../remote/RemotingInstrumentation.scala | 76 ++--- .../remote/ShardingInstrumentation.scala | 65 ++-- .../remote/artery/KamonRemoteInstrument.scala | 18 +- .../internal/ArterySerializationAdvice.scala | 29 +- .../remote/internal/KamonOptionVal.scala | 3 +- ...decConstructMessageMethodInterceptor.scala | 27 +- ...tobufCodecDecodeMessageMethodAdvisor.scala | 8 +- .../pekko/ActorCellInstrumentationSpec.scala | 10 +- .../pekko/ActorGroupMetricsSpec.scala | 35 ++- .../ActorLoggingInstrumentationSpec.scala | 11 +- .../pekko/ActorMetricsSpec.scala | 77 +++-- .../pekko/ActorMetricsTestActor.scala | 1 - .../pekko/ActorSystemMetricsSpec.scala | 4 +- .../pekko/AskPatternInstrumentationSpec.scala | 4 +- .../pekko/AutoGroupingSpec.scala | 8 +- .../pekko/DispatcherMetricsSpec.scala | 24 +- .../instrumentation/pekko/EnvelopeSpec.scala | 5 +- .../pekko/MessageTracingSpec.scala | 27 +- .../pekko/RouterMetricsSpec.scala | 78 ++--- .../pekko/RouterMetricsTestActor.scala | 1 - .../pekko/SchedulerInstrumentationSpec.scala | 3 +- .../SystemMessageInstrumentationSpec.scala | 20 +- .../instrumentation/pekko/TestLogger.scala | 2 +- .../ShardingInstrumentationSpec.scala | 28 +- .../ShardingMessageBufferingSpec.scala | 30 +- .../instrumentation/play/GuiceModule.scala | 6 +- .../play/PlayClientInstrumentation.scala | 2 +- .../play/PlayServerInstrumentation.scala | 87 +++--- .../play/RouterOperationNameGenerator.scala | 10 +- .../jedis/JedisInstrumentation.scala | 19 +- .../lettuce/LettuceInstrumentation.scala | 17 +- .../rediscala/RediscalaInstrumentation.scala | 22 +- .../combined/RedisInstrumentationsSpec.scala | 16 +- .../scala/FutureChainingInstrumentation.scala | 4 +- .../scala/FutureInstrumentationSpec.scala | 1 - .../scalaz/FutureInstrumentationSpec.scala | 1 - .../spring/client/ClientInstrumentation.scala | 4 +- .../server/CallableContextWrapper.scala | 3 +- .../server/SpringMVCInstrumentation.scala | 18 +- .../SpringClientInstrumentationSpec.scala | 3 +- .../SpringMVCInstrumentationSpec.scala | 5 +- .../system/host/HostMetrics.scala | 71 +++-- .../system/host/HostMetricsCollector.scala | 13 +- .../system/jvm/JvmMetrics.scala | 111 ++++--- .../system/jvm/JvmMetricsCollector.scala | 133 ++++---- .../system/process/ProcessMetrics.scala | 7 +- .../process/ProcessMetricsCollector.scala | 9 +- .../tapir/TapirInstrumentation.scala | 4 +- .../instrumentation/tapir/TapirSpec.scala | 9 +- .../instrumentation/tapir/TestRoutes.scala | 2 +- .../TwitterFutureInstrumentation.scala | 3 +- .../twitter/FutureInstrumentationSpec.scala | 4 +- .../zio2/ZIO2Instrumentation.scala | 9 +- .../zio2/ZIO2InstrumentationSpec.scala | 52 ++-- .../src/main/scala/kamon/apm/ApiClient.scala | 26 +- .../src/main/scala/kamon/apm/KamonApm.scala | 58 ++-- .../src/main/scala/kamon/apm/package.scala | 49 ++- .../test/scala/kamon/apm/ReporterSpec.scala | 44 ++- .../kamon/datadog/DatadogAPIReporter.scala | 52 +++- .../kamon/datadog/DatadogAgentReporter.scala | 60 ++-- .../kamon/datadog/DatadogSpanReporter.scala | 14 +- .../src/main/scala/kamon/datadog/DdSpan.scala | 23 +- .../main/scala/kamon/datadog/package.scala | 23 +- .../datadog/DatadogAPIReporterSpec.scala | 12 +- .../datadog/DatadogMetricSenderSpec.scala | 58 ++-- .../datadog/DatadogSpanReporterSpec.scala | 44 +-- .../kamon/graphite/GraphiteReporter.scala | 54 ++-- .../kamon/graphite/GraphiteReporterSpec.scala | 23 +- .../kamon/graphite/GraphiteSenderSpec.scala | 104 ++++--- .../kamon/influxdb/InfluxDBReporter.scala | 88 ++++-- .../influxdb/InfluxDBCustomMatchers.scala | 5 +- .../kamon/influxdb/InfluxDBReporterSpec.scala | 10 +- .../scala/kamon/jaeger/JaegerClient.scala | 15 +- .../scala/kamon/jaeger/JaegerReporter.scala | 1 - .../scala/kamon/newrelic/AttributeBuddy.scala | 4 +- .../scala/kamon/newrelic/NewRelicConfig.scala | 21 +- .../newrelic/metrics/ConversionSupport.scala | 2 +- .../newrelic/metrics/NewRelicCounters.scala | 8 +- .../metrics/NewRelicDistributionMetrics.scala | 18 +- .../newrelic/metrics/NewRelicGauges.scala | 7 +- .../metrics/NewRelicMetricsReporter.scala | 5 +- .../spans/NewRelicSpanConverter.scala | 4 +- .../newrelic/spans/NewRelicSpanReporter.scala | 12 +- .../spans/SpanBatchSenderBuilder.scala | 6 +- .../kamon/newrelic/AttributeBuddySpec.scala | 5 +- .../metrics/NewRelicCountersSpec.scala | 6 +- .../NewRelicDistributionMetricsSpec.scala | 11 +- .../metrics/NewRelicMetricsReporterSpec.scala | 103 +++++-- .../newrelic/metrics/TestMetricHelper.scala | 38 ++- .../spans/NewRelicSpanReporterSpec.scala | 11 +- .../kamon/newrelic/spans/TestSpanHelper.scala | 7 +- .../otel/OpenTelemetryTraceReporter.scala | 37 ++- .../main/scala/kamon/otel/SpanConverter.scala | 44 ++- .../main/scala/kamon/otel/TraceService.scala | 26 +- .../otel/OpenTelemetryTraceReporterSpec.scala | 37 ++- .../scala/kamon/otel/SpanConverterSpec.scala | 43 ++- .../scala/kamon/otel/TraceServiceSpec.scala | 5 +- .../scala/kamon/prometheus/HttpClient.scala | 8 +- .../prometheus/MetricOverrideReporter.scala | 32 +- .../PrometheusPushgatewayReporter.scala | 15 +- .../kamon/prometheus/PrometheusReporter.scala | 52 ++-- .../kamon/prometheus/ScrapeDataBuilder.scala | 127 ++++---- .../embeddedhttp/SunEmbeddedHttpServer.scala | 3 +- .../prometheus/EmbeddedHttpServerSpec.scala | 39 +-- .../prometheus/KamonTestSnapshotSupport.scala | 15 +- .../MetricOverrideReporterSpec.scala | 22 +- .../prometheus/ScrapeDataBuilderSpec.scala | 106 ++++--- .../statsd/SimpleMetricKeyGenerator.scala | 5 +- .../scala/kamon/statsd/StatsDReporter.scala | 72 +++-- .../src/main/scala/kamon/statsd/package.scala | 22 +- .../statsd/MetricDataPacketBufferSpec.scala | 21 +- .../kamon/statsd/ReadConfigUnitSpec.scala | 29 +- .../statsd/SimpleMetricKeyGeneratorSpec.scala | 78 +++-- .../kamon/statsd/StatsDReporterSpec.scala | 24 +- .../scala/kamon/statsd/StatsDServer.scala | 2 +- .../scala/kamon/zipkin/ZipkinReporter.scala | 22 +- .../kamon/zipkin/SpanConversionSpec.scala | 3 +- 385 files changed, 5988 insertions(+), 4232 deletions(-) diff --git a/bundle/kamon-runtime-attacher/src/main/scala/kamon/runtime/Attacher.scala b/bundle/kamon-runtime-attacher/src/main/scala/kamon/runtime/Attacher.scala index d98739eb8..fbc9fe4c2 100644 --- a/bundle/kamon-runtime-attacher/src/main/scala/kamon/runtime/Attacher.scala +++ b/bundle/kamon-runtime-attacher/src/main/scala/kamon/runtime/Attacher.scala @@ -58,11 +58,12 @@ object Attacher { */ private def isKanelaLoaded(): Boolean = { val isLoadedProperty = java.lang.Boolean.parseBoolean(System.getProperty("kanela.loaded")) - val hasKanelaClasses = try { - Class.forName("kanela.agent.Kanela", false, ClassLoader.getSystemClassLoader) != null - } catch { - case _: Throwable => false - } + val hasKanelaClasses = + try { + Class.forName("kanela.agent.Kanela", false, ClassLoader.getSystemClassLoader) != null + } catch { + case _: Throwable => false + } hasKanelaClasses && isLoadedProperty } @@ -78,7 +79,6 @@ object Attacher { .filter(cl => cl.getClass.getName == "org.springframework.boot.loader.LaunchedURLClassLoader") } - /** * Reloads the Kanela agent. This will cause all instrumentation definitions to be dropped and re-initialized. */ diff --git a/core/kamon-core-bench/src/main/scala/kamon/bench/TagSetCreationBenchmark.scala b/core/kamon-core-bench/src/main/scala/kamon/bench/TagSetCreationBenchmark.scala index 2a1f31b2d..209ea4bd6 100644 --- a/core/kamon-core-bench/src/main/scala/kamon/bench/TagSetCreationBenchmark.scala +++ b/core/kamon-core-bench/src/main/scala/kamon/bench/TagSetCreationBenchmark.scala @@ -34,11 +34,11 @@ class TagSetCreationBenchmark { def createTagSetFromIndividualKeys(): TagSet = { var tags = TagSet.Empty tags = tags.withTag("http.method", "POST") - if(tagCount > 1) tags = tags.withTag("http.url", "http://localhost:8080/test") - if(tagCount > 2) tags = tags.withTag("http.status_code", 200L) - if(tagCount > 3) tags = tags.withTag("error", false) - if(tagCount > 4) tags = tags.withTag("userID", "abcdef") - if(tagCount > 5) tags = tags.withTag("correlationID", "0123456") + if (tagCount > 1) tags = tags.withTag("http.url", "http://localhost:8080/test") + if (tagCount > 2) tags = tags.withTag("http.status_code", 200L) + if (tagCount > 3) tags = tags.withTag("error", false) + if (tagCount > 4) tags = tags.withTag("userID", "abcdef") + if (tagCount > 5) tags = tags.withTag("correlationID", "0123456") tags } @@ -47,11 +47,11 @@ class TagSetCreationBenchmark { def createTagSetFromBuilder(): TagSet = { val tags = TagSet.builder() tags.add("http.method", "POST") - if(tagCount > 1) tags.add("http.url", "http://localhost:8080/test") - if(tagCount > 2) tags.add("http.status_code", 200L) - if(tagCount > 3) tags.add("error", false) - if(tagCount > 4) tags.add("userID", "abcdef") - if(tagCount > 5) tags.add("correlationID", "0123456") + if (tagCount > 1) tags.add("http.url", "http://localhost:8080/test") + if (tagCount > 2) tags.add("http.status_code", 200L) + if (tagCount > 3) tags.add("error", false) + if (tagCount > 4) tags.add("userID", "abcdef") + if (tagCount > 5) tags.add("correlationID", "0123456") tags.build() } diff --git a/core/kamon-core-bench/src/main/scala/kamon/bench/TagSetLookupBenchmark.scala b/core/kamon-core-bench/src/main/scala/kamon/bench/TagSetLookupBenchmark.scala index 55fbf0193..c5c04b6c1 100644 --- a/core/kamon-core-bench/src/main/scala/kamon/bench/TagSetLookupBenchmark.scala +++ b/core/kamon-core-bench/src/main/scala/kamon/bench/TagSetLookupBenchmark.scala @@ -43,7 +43,6 @@ class TagSetLookupBenchmark { .withTag("userID", "abcdef") .withTag("correlationID", "0123456") - val builderLeft = builderTags() val builderRight = builderTags() val keyByKeyLeft = keyByKeyTags() diff --git a/core/kamon-core-bench/src/main/scala/kamon/bench/ThreadLocalStorageBenchmark.scala b/core/kamon-core-bench/src/main/scala/kamon/bench/ThreadLocalStorageBenchmark.scala index 531227cb1..01b7a02f8 100644 --- a/core/kamon-core-bench/src/main/scala/kamon/bench/ThreadLocalStorageBenchmark.scala +++ b/core/kamon-core-bench/src/main/scala/kamon/bench/ThreadLocalStorageBenchmark.scala @@ -28,9 +28,8 @@ class ThreadLocalStorageBenchmark { val TestKey: Context.Key[Int] = Context.key("test-key", 0) val ContextWithKey: Context = Context.of(TestKey, 43) - val CrossTLS: Storage = new CrossThreadLocal - val FTLS: Storage = new Storage.ThreadLocal - + val CrossTLS: Storage = new CrossThreadLocal + val FTLS: Storage = new Storage.ThreadLocal @Benchmark @BenchmarkMode(Array(Mode.AverageTime)) diff --git a/core/kamon-core-tests/src/test/scala/kamon/InitialConfigLoadingSpec.scala b/core/kamon-core-tests/src/test/scala/kamon/InitialConfigLoadingSpec.scala index 04e2b5e39..7a4c7832a 100644 --- a/core/kamon-core-tests/src/test/scala/kamon/InitialConfigLoadingSpec.scala +++ b/core/kamon-core-tests/src/test/scala/kamon/InitialConfigLoadingSpec.scala @@ -15,7 +15,8 @@ class InitialConfigLoadingSpec extends AnyWordSpec with Matchers with Eventually "the initial config loading" should { "fallback to using reference configuration only when application.conf files are malformed" in { - val process = Runtime.getRuntime.exec(createProcessWithConfig("kamon.KamonWithCustomConfig", "{This is a bad config}")) + val process = + Runtime.getRuntime.exec(createProcessWithConfig("kamon.KamonWithCustomConfig", "{This is a bad config}")) val processOutputReader = new BufferedReader(new InputStreamReader(process.getInputStream())) eventually(timeout(10 seconds)) { @@ -23,7 +24,7 @@ class InitialConfigLoadingSpec extends AnyWordSpec with Matchers with Eventually outputLine shouldBe "All Good" } - if(process.isAlive) { + if (process.isAlive) { process.destroyForcibly().waitFor(5, TimeUnit.SECONDS) } } @@ -50,4 +51,4 @@ object KamonWithCustomConfig extends App { case Failure(_) => println("All Bad") } -} \ No newline at end of file +} diff --git a/core/kamon-core-tests/src/test/scala/kamon/KamonLifecycleSpec.scala b/core/kamon-core-tests/src/test/scala/kamon/KamonLifecycleSpec.scala index 9ee207d96..3194e261f 100644 --- a/core/kamon-core-tests/src/test/scala/kamon/KamonLifecycleSpec.scala +++ b/core/kamon-core-tests/src/test/scala/kamon/KamonLifecycleSpec.scala @@ -52,7 +52,6 @@ class KamonLifecycleSpec extends AnyWordSpec with Matchers with Eventually { } } - def createProcessCommand(mainClass: String): String = { System.getProperty("java.home") + File.separator + "bin" + File.separator + "java" + " -cp " + System.getProperty("java.class.path") + " " + mainClass @@ -95,7 +94,7 @@ object UsingKamonApisWithoutInit extends App { .asScala .filter(_.getName.startsWith("kamon")) - if(allKamonThreadNames.nonEmpty) + if (allKamonThreadNames.nonEmpty) sys.error("Kamon shouldn't start or create threads until init is called") } diff --git a/core/kamon-core-tests/src/test/scala/kamon/UtilsOnConfigSpec.scala b/core/kamon-core-tests/src/test/scala/kamon/UtilsOnConfigSpec.scala index aff97ce8a..4c294e6df 100644 --- a/core/kamon-core-tests/src/test/scala/kamon/UtilsOnConfigSpec.scala +++ b/core/kamon-core-tests/src/test/scala/kamon/UtilsOnConfigSpec.scala @@ -37,15 +37,15 @@ class UtilsOnConfigSpec extends AnyWordSpec with Matchers { "the utils on config syntax" should { "list all top level keys with a configuration" in { - config.getConfig("kamon.test").topLevelKeys should contain only("configuration-one", "config.two") + config.getConfig("kamon.test").topLevelKeys should contain only ("configuration-one", "config.two") } - "create a map from top level keys to the inner configuration objects"in { + "create a map from top level keys to the inner configuration objects" in { val extractedConfigurations = config.getConfig("kamon.test").configurations - extractedConfigurations.keys should contain only("configuration-one", "config.two") - extractedConfigurations("configuration-one").topLevelKeys should contain only("setting", "other-setting") - extractedConfigurations("config.two").topLevelKeys should contain only("setting") + extractedConfigurations.keys should contain only ("configuration-one", "config.two") + extractedConfigurations("configuration-one").topLevelKeys should contain only ("setting", "other-setting") + extractedConfigurations("config.two").topLevelKeys should contain only ("setting") } } diff --git a/core/kamon-core-tests/src/test/scala/kamon/context/BinaryPropagationSpec.scala b/core/kamon-core-tests/src/test/scala/kamon/context/BinaryPropagationSpec.scala index cfa5a88c8..f57629e81 100644 --- a/core/kamon-core-tests/src/test/scala/kamon/context/BinaryPropagationSpec.scala +++ b/core/kamon-core-tests/src/test/scala/kamon/context/BinaryPropagationSpec.scala @@ -36,8 +36,10 @@ class BinaryPropagationSpec extends AnyWordSpec with Matchers with OptionValues "handle read failures in an entry reader" in { val context = Context.of( - BinaryPropagationSpec.StringKey, "string-value", - BinaryPropagationSpec.FailStringKey, "fail-read" + BinaryPropagationSpec.StringKey, + "string-value", + BinaryPropagationSpec.FailStringKey, + "fail-read" ) val writer = inspectableByteStreamWriter() binaryPropagation.write(context, writer) @@ -50,8 +52,10 @@ class BinaryPropagationSpec extends AnyWordSpec with Matchers with OptionValues "handle write failures in an entry writer" in { val context = Context.of( - BinaryPropagationSpec.StringKey, "string-value", - BinaryPropagationSpec.FailStringKey, "fail-write" + BinaryPropagationSpec.StringKey, + "string-value", + BinaryPropagationSpec.FailStringKey, + "fail-write" ) val writer = inspectableByteStreamWriter() binaryPropagation.write(context, writer) @@ -120,8 +124,8 @@ class BinaryPropagationSpec extends AnyWordSpec with Matchers with OptionValues |entries.outgoing.failString = "kamon.context.BinaryPropagationSpec$FailStringEntryCodec" | """.stripMargin - ).withFallback(ConfigFactory.load().getConfig("kamon.propagation"))) - + ).withFallback(ConfigFactory.load().getConfig("kamon.propagation")) + ) def inspectableByteStreamWriter() = new ByteArrayOutputStream(32) with ByteStreamWriter @@ -138,14 +142,14 @@ object BinaryPropagationSpec { override def read(medium: ByteStreamReader, context: Context): Context = { val valueData = medium.readAll() - if(valueData.length > 0) { + if (valueData.length > 0) { context.withEntry(StringKey, new String(valueData)) } else context } override def write(context: Context, medium: ByteStreamWriter): Unit = { val value = context.get(StringKey) - if(value != null) { + if (value != null) { medium.write(value.getBytes) } } @@ -156,9 +160,9 @@ object BinaryPropagationSpec { override def read(medium: ByteStreamReader, context: Context): Context = { val valueData = medium.readAll() - if(valueData.length > 0) { + if (valueData.length > 0) { val stringValue = new String(valueData) - if(stringValue == "fail-read") { + if (stringValue == "fail-read") { sys.error("The fail string entry reader has triggered") } @@ -168,7 +172,7 @@ object BinaryPropagationSpec { override def write(context: Context, medium: ByteStreamWriter): Unit = { val value = context.get(FailStringKey) - if(value != null && value != "fail-write") { + if (value != null && value != "fail-write") { medium.write(value.getBytes) } else { medium.write(42) // malformed data on purpose @@ -176,4 +180,4 @@ object BinaryPropagationSpec { } } } -} \ No newline at end of file +} diff --git a/core/kamon-core-tests/src/test/scala/kamon/context/HttpPropagationSpec.scala b/core/kamon-core-tests/src/test/scala/kamon/context/HttpPropagationSpec.scala index 9d32439cd..7b05f5193 100644 --- a/core/kamon-core-tests/src/test/scala/kamon/context/HttpPropagationSpec.scala +++ b/core/kamon-core-tests/src/test/scala/kamon/context/HttpPropagationSpec.scala @@ -69,17 +69,16 @@ class HttpPropagationSpec extends AnyWordSpec with Matchers with OptionValues { context.getTag(plain("hello")) shouldBe "world" context.getTag(option("correlation")).value shouldBe "1234" context.getTag(option("unknown")) shouldBe empty - context.getTag(option("myLocalTag")) shouldBe empty //should be removed by the filter - context.getTag(option("privateMappedTag")) shouldBe empty //should be removed by the filter + context.getTag(option("myLocalTag")) shouldBe empty // should be removed by the filter + context.getTag(option("privateMappedTag")) shouldBe empty // should be removed by the filter } } - "writing to outgoing requests" should { "at least write the upstream name when the context is empty" in { val headers = mutable.Map.empty[String, String] httpPropagation.write(Context.Empty, headerWriterFromMap(headers)) - headers should contain only( + headers should contain only ( "x-content-tags" -> "upstream.name=kamon-application;" ) } @@ -92,7 +91,7 @@ class HttpPropagationSpec extends AnyWordSpec with Matchers with OptionValues { ))) httpPropagation.write(context, headerWriterFromMap(headers)) - headers should contain only( + headers should contain only ( "x-content-tags" -> "hello=world;upstream.name=kamon-application;", "x-mapped-tag" -> "value" ) @@ -101,15 +100,17 @@ class HttpPropagationSpec extends AnyWordSpec with Matchers with OptionValues { "write context entries when available" in { val headers = mutable.Map.empty[String, String] val context = Context.of( - HttpPropagationSpec.StringKey, "out-we-go", - HttpPropagationSpec.IntegerKey, 42 + HttpPropagationSpec.StringKey, + "out-we-go", + HttpPropagationSpec.IntegerKey, + 42 ) httpPropagation.write(context, headerWriterFromMap(headers)) - headers should contain only( + headers should contain only ( "x-content-tags" -> "upstream.name=kamon-application;", "string-header" -> "out-we-go" - ) + ) } "not write filtered context tags" in { @@ -117,13 +118,13 @@ class HttpPropagationSpec extends AnyWordSpec with Matchers with OptionValues { val context = Context.of(TagSet.from(Map( "hello" -> "world", "mappedTag" -> "value", - "privateHello" -> "world", //should be filtered - "privateMappedTag" -> "value", //should be filtered - "myLocalTag" -> "value" //should be filtered + "privateHello" -> "world", // should be filtered + "privateMappedTag" -> "value", // should be filtered + "myLocalTag" -> "value" // should be filtered ))) httpPropagation.write(context, headerWriterFromMap(headers)) - headers should contain only( + headers should contain only ( "x-content-tags" -> "hello=world;upstream.name=kamon-application;", "x-mapped-tag" -> "value" ) @@ -132,7 +133,6 @@ class HttpPropagationSpec extends AnyWordSpec with Matchers with OptionValues { } } - val httpPropagation = HttpPropagation.from( ConfigFactory.parseString( """ @@ -150,12 +150,13 @@ class HttpPropagationSpec extends AnyWordSpec with Matchers with OptionValues { |entries.outgoing.string = "kamon.context.HttpPropagationSpec$StringEntryCodec" | """.stripMargin - ).withFallback(ConfigFactory.load().getConfig("kamon.propagation")), identifierScheme = "single") - + ).withFallback(ConfigFactory.load().getConfig("kamon.propagation")), + identifierScheme = "single" + ) def headerReaderFromMap(map: Map[String, String]): HttpPropagation.HeaderReader = new HttpPropagation.HeaderReader { override def read(header: String): Option[String] = { - if(map.get("fail").nonEmpty) + if (map.get("fail").nonEmpty) sys.error("failing on purpose") map.get(header) @@ -164,9 +165,10 @@ class HttpPropagationSpec extends AnyWordSpec with Matchers with OptionValues { override def readAll(): Map[String, String] = map } - def headerWriterFromMap(map: mutable.Map[String, String]): HttpPropagation.HeaderWriter = new HttpPropagation.HeaderWriter { - override def write(header: String, value: String): Unit = map.put(header, value) - } + def headerWriterFromMap(map: mutable.Map[String, String]): HttpPropagation.HeaderWriter = + new HttpPropagation.HeaderWriter { + override def write(header: String, value: String): Unit = map.put(header, value) + } } object HttpPropagationSpec { @@ -175,7 +177,6 @@ object HttpPropagationSpec { val IntegerKey = Context.key[Int]("integer", 0) val OptionalKey = Context.key[Option[String]]("optional", None) - class StringEntryCodec extends EntryReader[HeaderReader] with EntryWriter[HeaderWriter] { private val HeaderName = "string-header" @@ -198,4 +199,4 @@ object HttpPropagationSpec { } } -} \ No newline at end of file +} diff --git a/core/kamon-core-tests/src/test/scala/kamon/context/ThreadLocalStorageSpec.scala b/core/kamon-core-tests/src/test/scala/kamon/context/ThreadLocalStorageSpec.scala index 246c60b4a..1d8e35f36 100644 --- a/core/kamon-core-tests/src/test/scala/kamon/context/ThreadLocalStorageSpec.scala +++ b/core/kamon-core-tests/src/test/scala/kamon/context/ThreadLocalStorageSpec.scala @@ -15,7 +15,6 @@ package kamon.context - import kamon.context.Storage.Scope import org.scalatest.BeforeAndAfterAll import org.scalatest.concurrent.ScalaFutures._ @@ -48,7 +47,7 @@ class ThreadLocalStorageSpec extends AnyWordSpec with Matchers with BeforeAndAft TLS.current() shouldBe Context.Empty val scope = TLS.store(ScopeWithKey) - TLS.current() shouldBe theSameInstanceAs(ScopeWithKey) + TLS.current() shouldBe theSameInstanceAs(ScopeWithKey) scope.close() TLS.current() shouldBe Context.Empty diff --git a/core/kamon-core-tests/src/test/scala/kamon/metric/CounterSpec.scala b/core/kamon-core-tests/src/test/scala/kamon/metric/CounterSpec.scala index 4d144c8f7..19ce594b2 100644 --- a/core/kamon-core-tests/src/test/scala/kamon/metric/CounterSpec.scala +++ b/core/kamon-core-tests/src/test/scala/kamon/metric/CounterSpec.scala @@ -24,7 +24,8 @@ import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec import kamon.metric.Counter.delta -class CounterSpec extends AnyWordSpec with Matchers with InstrumentInspection.Syntax with Eventually with InitAndStopKamonAfterAll { +class CounterSpec extends AnyWordSpec with Matchers with InstrumentInspection.Syntax with Eventually + with InitAndStopKamonAfterAll { "a Counter" should { "allow unit and bundled increments" in { @@ -88,7 +89,8 @@ class CounterSpec extends AnyWordSpec with Matchers with InstrumentInspection.Sy var last = numbers.head override def get(): Long = synchronized { - if(remaining.isEmpty) last else { + if (remaining.isEmpty) last + else { val head = remaining.head remaining = remaining.tail last = head diff --git a/core/kamon-core-tests/src/test/scala/kamon/metric/GaugeSpec.scala b/core/kamon-core-tests/src/test/scala/kamon/metric/GaugeSpec.scala index 031768a13..fae3c7972 100644 --- a/core/kamon-core-tests/src/test/scala/kamon/metric/GaugeSpec.scala +++ b/core/kamon-core-tests/src/test/scala/kamon/metric/GaugeSpec.scala @@ -25,58 +25,55 @@ class GaugeSpec extends AnyWordSpec with Matchers with InstrumentInspection.Synt "a Gauge" should { "have a starting value of zero" in { val gauge = Kamon.gauge("default-value").withoutTags() - gauge.value shouldBe 0D + gauge.value shouldBe 0d } "retain the last value recorded on it" in { - val gauge = Kamon.gauge("retain-value").withoutTags().update(42D) - gauge.value shouldBe 42D - gauge.value shouldBe 42D + val gauge = Kamon.gauge("retain-value").withoutTags().update(42d) + gauge.value shouldBe 42d + gauge.value shouldBe 42d - gauge.update(17D) - gauge.value shouldBe 17D - gauge.value shouldBe 17D + gauge.update(17d) + gauge.value shouldBe 17d + gauge.value shouldBe 17d } "ignore updates with negative values" in { val gauge = Kamon.gauge("non-negative-value").withoutTags().update(30) - gauge.value shouldBe 30D - gauge.update(-20D) - gauge.value shouldBe 30D + gauge.value shouldBe 30d + gauge.update(-20d) + gauge.value shouldBe 30d gauge.decrement(100) - gauge.value shouldBe 30D + gauge.value shouldBe 30d gauge.increment(-100) - gauge.value shouldBe 30D + gauge.value shouldBe 30d } "increment and decrement the current value of the gauge" in { val gauge = Kamon.gauge("increment-decrement").withoutTags().update(30) - gauge.value shouldBe 30D - gauge.increment(10D) - gauge.increment(10D) - gauge.value shouldBe 50D + gauge.value shouldBe 30d + gauge.increment(10d) + gauge.increment(10d) + gauge.value shouldBe 50d gauge.decrement(15) - gauge.decrement(15D) - gauge.value shouldBe 20D + gauge.decrement(15d) + gauge.value shouldBe 20d } "increment and decrement the current value of the gauge with non whole values" in { val gauge = Kamon.gauge("increment-decrement").withoutTags().update(30) - gauge.value shouldBe 30D - gauge.increment(10.5D) - gauge.increment(10.5D) - gauge.value shouldBe 51D - - gauge.decrement(10.5D) - gauge.decrement(10.5D) - gauge.value shouldBe 30D + gauge.value shouldBe 30d + gauge.increment(10.5d) + gauge.increment(10.5d) + gauge.value shouldBe 51d + + gauge.decrement(10.5d) + gauge.decrement(10.5d) + gauge.value shouldBe 30d } - - - } } diff --git a/core/kamon-core-tests/src/test/scala/kamon/metric/HistogramSpec.scala b/core/kamon-core-tests/src/test/scala/kamon/metric/HistogramSpec.scala index 89d3156d8..db0fc634c 100644 --- a/core/kamon-core-tests/src/test/scala/kamon/metric/HistogramSpec.scala +++ b/core/kamon-core-tests/src/test/scala/kamon/metric/HistogramSpec.scala @@ -21,7 +21,6 @@ import kamon.testkit.InstrumentInspection import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec - class HistogramSpec extends AnyWordSpec with Matchers with InstrumentInspection.Syntax { "a Histogram" should { @@ -32,9 +31,9 @@ class HistogramSpec extends AnyWordSpec with Matchers with InstrumentInspection. histogram.record(200) val distribution = histogram.distribution() - distribution.min shouldBe(100) - distribution.max shouldBe(200) - distribution.count shouldBe(1000) + distribution.min shouldBe (100) + distribution.max shouldBe (200) + distribution.count shouldBe (1000) distribution.buckets.length shouldBe 3 distribution.buckets.map(b => (b.value, b.frequency)) should contain.allOf( (100 -> 1), @@ -43,16 +42,19 @@ class HistogramSpec extends AnyWordSpec with Matchers with InstrumentInspection. ) val emptyDistribution = histogram.distribution() - emptyDistribution.min shouldBe(0) - emptyDistribution.max shouldBe(0) - emptyDistribution.count shouldBe(0) + emptyDistribution.min shouldBe (0) + emptyDistribution.max shouldBe (0) + emptyDistribution.count shouldBe (0) emptyDistribution.buckets.length shouldBe 0 } "accept a smallest discernible value configuration" in { // The lowestDiscernibleValue gets rounded down to the closest power of 2, so, here it will be 64. - val histogram = Kamon.histogram("test-lowest-discernible-value", unit = time.nanoseconds, - dynamicRange = DynamicRange.Fine.withLowestDiscernibleValue(100)).withoutTags() + val histogram = Kamon.histogram( + "test-lowest-discernible-value", + unit = time.nanoseconds, + dynamicRange = DynamicRange.Fine.withLowestDiscernibleValue(100) + ).withoutTags() histogram.record(100) histogram.record(200) histogram.record(300) @@ -61,9 +63,9 @@ class HistogramSpec extends AnyWordSpec with Matchers with InstrumentInspection. histogram.record(3000) val distribution = histogram.distribution() - distribution.min shouldBe(64) - distribution.max shouldBe(2944) - distribution.count shouldBe(6) + distribution.min shouldBe (64) + distribution.max shouldBe (2944) + distribution.count shouldBe (6) distribution.buckets.length shouldBe 6 distribution.buckets.map(b => (b.value, b.frequency)) should contain.allOf( (64 -> 1), @@ -80,9 +82,9 @@ class HistogramSpec extends AnyWordSpec with Matchers with InstrumentInspection. (1L to 10L).foreach(histogram.record) val distribution = histogram.distribution() - distribution.percentile(99).rank shouldBe(99) - distribution.percentile(99.9).rank shouldBe(99.9) - distribution.percentile(99.99).rank shouldBe(99.99D) + distribution.percentile(99).rank shouldBe (99) + distribution.percentile(99.9).rank shouldBe (99.9) + distribution.percentile(99.99).rank shouldBe (99.99d) } "[private api] record values and optionally keep the internal state when a snapshot is taken" in { @@ -96,9 +98,9 @@ class HistogramSpec extends AnyWordSpec with Matchers with InstrumentInspection. histogram.distribution(resetState = false) } - distribution.min shouldBe(100) - distribution.max shouldBe(200) - distribution.count shouldBe(1000) + distribution.min shouldBe (100) + distribution.max shouldBe (200) + distribution.count shouldBe (1000) distribution.buckets.length shouldBe 3 distribution.buckets.map(b => (b.value, b.frequency)) should contain.allOf( (100 -> 1), @@ -107,4 +109,4 @@ class HistogramSpec extends AnyWordSpec with Matchers with InstrumentInspection. ) } } -} \ No newline at end of file +} diff --git a/core/kamon-core-tests/src/test/scala/kamon/metric/InstrumentGroupSpec.scala b/core/kamon-core-tests/src/test/scala/kamon/metric/InstrumentGroupSpec.scala index d0b08a9c7..63c9f6cc9 100644 --- a/core/kamon-core-tests/src/test/scala/kamon/metric/InstrumentGroupSpec.scala +++ b/core/kamon-core-tests/src/test/scala/kamon/metric/InstrumentGroupSpec.scala @@ -6,16 +6,16 @@ import kamon.testkit.MetricInspection import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec -class InstrumentGroupSpec extends AnyWordSpec with Matchers with MetricInspection.Syntax { +class InstrumentGroupSpec extends AnyWordSpec with Matchers with MetricInspection.Syntax { "an Instrument Group" should { "register instruments with common tags and remove them when cleaning up" in { val group = new CommonTagsOnly(TagSet.of("type", "common")) - Counter.tagValues("type") should contain only("common") - Gauge.tagValues("type") should contain only("common") - Histogram.tagValues("type") should contain only("common") - RangeSampler.tagValues("type") should contain only("common") + Counter.tagValues("type") should contain only ("common") + Gauge.tagValues("type") should contain only ("common") + Histogram.tagValues("type") should contain only ("common") + RangeSampler.tagValues("type") should contain only ("common") group.remove() @@ -28,10 +28,10 @@ class InstrumentGroupSpec extends AnyWordSpec with Matchers with MetricInspectio "override common tags with tags supplied to the register method" in { val group = new MixedTags(TagSet.of("type", "basic")) - Counter.tagValues("type") should contain only("basic") - Gauge.tagValues("type") should contain only("simple") - Histogram.tagValues("type") should contain only("42") - RangeSampler.tagValues("type") should contain only("true") + Counter.tagValues("type") should contain only ("basic") + Gauge.tagValues("type") should contain only ("simple") + Histogram.tagValues("type") should contain only ("42") + RangeSampler.tagValues("type") should contain only ("true") group.remove() @@ -42,7 +42,6 @@ class InstrumentGroupSpec extends AnyWordSpec with Matchers with MetricInspectio } } - val Counter = Kamon.counter("metric.group.counter") val Gauge = Kamon.gauge("metric.group.gauge") val Histogram = Kamon.histogram("metric.group.histogram") @@ -61,4 +60,4 @@ class InstrumentGroupSpec extends AnyWordSpec with Matchers with MetricInspectio val histogram = register(Histogram, "type", 42) val rangeSampler = register(RangeSampler, "type", true) } -} \ No newline at end of file +} diff --git a/core/kamon-core-tests/src/test/scala/kamon/metric/MetricLookupSpec.scala b/core/kamon-core-tests/src/test/scala/kamon/metric/MetricLookupSpec.scala index 691677fea..9dad55bc0 100644 --- a/core/kamon-core-tests/src/test/scala/kamon/metric/MetricLookupSpec.scala +++ b/core/kamon-core-tests/src/test/scala/kamon/metric/MetricLookupSpec.scala @@ -55,31 +55,31 @@ class MetricLookupSpec extends AnyWordSpec with Matchers { Kamon.counter("original-counter") Kamon.gauge("original-counter") - } should have message(redefinitionError("original-counter", "counter", "gauge")) + } should have message (redefinitionError("original-counter", "counter", "gauge")) the[IllegalArgumentException] thrownBy { Kamon.counter("original-counter") Kamon.histogram("original-counter") - } should have message(redefinitionError("original-counter", "counter", "histogram")) + } should have message (redefinitionError("original-counter", "counter", "histogram")) the[IllegalArgumentException] thrownBy { Kamon.counter("original-counter") Kamon.rangeSampler("original-counter") - } should have message(redefinitionError("original-counter", "counter", "rangeSampler")) + } should have message (redefinitionError("original-counter", "counter", "rangeSampler")) the[IllegalArgumentException] thrownBy { Kamon.counter("original-counter") Kamon.timer("original-counter") - } should have message(redefinitionError("original-counter", "counter", "timer")) + } should have message (redefinitionError("original-counter", "counter", "timer")) the[IllegalArgumentException] thrownBy { Kamon.histogram("original-histogram") Kamon.counter("original-histogram") - } should have message(redefinitionError("original-histogram", "histogram", "counter")) + } should have message (redefinitionError("original-histogram", "histogram", "counter")) } } @@ -114,7 +114,8 @@ class MetricLookupSpec extends AnyWordSpec with Matchers { "always return the same range-sampler for a set of tags" in { val rangeSamplerOne = Kamon.rangeSampler("range-sampler-lookup").withTag("tag", "value") val rangeSamplerTwo = Kamon.rangeSampler("range-sampler-lookup").withTag("tag", "value") - val rangeSamplerThree = Kamon.rangeSampler("range-sampler-lookup").withTags(TagSet.from(javaMap("tag", "value": Any))) + val rangeSamplerThree = + Kamon.rangeSampler("range-sampler-lookup").withTags(TagSet.from(javaMap("tag", "value": Any))) rangeSamplerOne shouldBe theSameInstanceAs(rangeSamplerTwo) rangeSamplerOne shouldBe theSameInstanceAs(rangeSamplerThree) diff --git a/core/kamon-core-tests/src/test/scala/kamon/metric/PeriodSnapshotAccumulatorSpec.scala b/core/kamon-core-tests/src/test/scala/kamon/metric/PeriodSnapshotAccumulatorSpec.scala index 67fa23606..e5f5441d2 100644 --- a/core/kamon-core-tests/src/test/scala/kamon/metric/PeriodSnapshotAccumulatorSpec.scala +++ b/core/kamon-core-tests/src/test/scala/kamon/metric/PeriodSnapshotAccumulatorSpec.scala @@ -41,15 +41,15 @@ class PeriodSnapshotAccumulatorSpec extends AnyWordSpec with Matchers with Recon "bypass accumulation if the configured duration is equal to the metric tick-interval, regardless of the snapshot" in { val accumulator = newAccumulator(10, 1) - accumulator.add(tenSeconds).value should be theSameInstanceAs(tenSeconds) - accumulator.add(fiveSecondsOne).value should be theSameInstanceAs(fiveSecondsOne) + accumulator.add(tenSeconds).value should be theSameInstanceAs (tenSeconds) + accumulator.add(fiveSecondsOne).value should be theSameInstanceAs (fiveSecondsOne) } "bypass accumulation if snapshots are beyond the expected next tick" in { val accumulator = newAccumulator(4, 1) accumulator.add(almostThreeSeconds) shouldBe empty accumulator.add(fourSeconds) shouldBe defined - accumulator.add(nineSeconds).value should be theSameInstanceAs(nineSeconds) + accumulator.add(nineSeconds).value should be theSameInstanceAs (nineSeconds) } "remove snapshots once they have been flushed" in { @@ -81,35 +81,35 @@ class PeriodSnapshotAccumulatorSpec extends AnyWordSpec with Matchers with Recon // The first snapshot will almost always be shorter than 15 seconds as it gets adjusted to the nearest initial period. val accumulator = newAccumulator(15, 0) - accumulator.add(fiveSecondsTwo) shouldBe empty // second 0:10 - val s15 = accumulator.add(fiveSecondsThree).value // second 0:15 - s15.from shouldBe(fiveSecondsTwo.from) - s15.to shouldBe(fiveSecondsThree.to) - - accumulator.add(fiveSecondsFour) shouldBe empty // second 0:20 - accumulator.add(fiveSecondsFive) shouldBe empty // second 0:25 - val s30 = accumulator.add(fiveSecondsSix).value // second 0:30 - s30.from shouldBe(fiveSecondsFour.from) - s30.to shouldBe(fiveSecondsSix.to) - - accumulator.add(fiveSecondsSeven) shouldBe empty // second 0:35 + accumulator.add(fiveSecondsTwo) shouldBe empty // second 0:10 + val s15 = accumulator.add(fiveSecondsThree).value // second 0:15 + s15.from shouldBe (fiveSecondsTwo.from) + s15.to shouldBe (fiveSecondsThree.to) + + accumulator.add(fiveSecondsFour) shouldBe empty // second 0:20 + accumulator.add(fiveSecondsFive) shouldBe empty // second 0:25 + val s30 = accumulator.add(fiveSecondsSix).value // second 0:30 + s30.from shouldBe (fiveSecondsFour.from) + s30.to shouldBe (fiveSecondsSix.to) + + accumulator.add(fiveSecondsSeven) shouldBe empty // second 0:35 } "do best effort to align when snapshots themselves are not aligned" in { val accumulator = newAccumulator(30, 0) - accumulator.add(tenSecondsOne) shouldBe empty // second 0:13 - accumulator.add(tenSecondsTwo) shouldBe empty // second 0:23 - val s23 = accumulator.add(tenSecondsThree).value // second 0:33 - s23.from shouldBe(tenSecondsOne.from) - s23.to shouldBe(tenSecondsThree.to) - - accumulator.add(tenSecondsFour) shouldBe empty // second 0:43 - accumulator.add(tenSecondsFive) shouldBe empty // second 0:53 - val s103 = accumulator.add(tenSecondsSix).value // second 1:03 - s103.from shouldBe(tenSecondsFour.from) - s103.to shouldBe(tenSecondsSix.to) - - accumulator.add(fiveSecondsSeven) shouldBe empty // second 1:13 + accumulator.add(tenSecondsOne) shouldBe empty // second 0:13 + accumulator.add(tenSecondsTwo) shouldBe empty // second 0:23 + val s23 = accumulator.add(tenSecondsThree).value // second 0:33 + s23.from shouldBe (tenSecondsOne.from) + s23.to shouldBe (tenSecondsThree.to) + + accumulator.add(tenSecondsFour) shouldBe empty // second 0:43 + accumulator.add(tenSecondsFive) shouldBe empty // second 0:53 + val s103 = accumulator.add(tenSecondsSix).value // second 1:03 + s103.from shouldBe (tenSecondsFour.from) + s103.to shouldBe (tenSecondsSix.to) + + accumulator.add(fiveSecondsSeven) shouldBe empty // second 1:13 } "allow to peek into the data that has been accumulated" in { @@ -117,26 +117,26 @@ class PeriodSnapshotAccumulatorSpec extends AnyWordSpec with Matchers with Recon accumulator.add(fiveSecondsOne) shouldBe empty accumulator.add(fiveSecondsTwo) shouldBe empty - for(_ <- 1 to 10) { + for (_ <- 1 to 10) { val peekSnapshot = accumulator.peek() val mergedHistogram = peekSnapshot.histograms.find(_.name == "histogram").get.instruments.head.value val mergedRangeSampler = peekSnapshot.rangeSamplers.find(_.name == "rangeSampler").get.instruments.head.value peekSnapshot.counters.find(_.name == "counter").get.instruments.head.value shouldBe (55) peekSnapshot.gauges.find(_.name == "gauge").get.instruments.head.value shouldBe (33) - mergedHistogram.buckets.map(_.value) should contain allOf(22L, 33L) - mergedRangeSampler.buckets.map(_.value) should contain allOf(22L, 33L) + mergedHistogram.buckets.map(_.value) should contain allOf (22L, 33L) + mergedRangeSampler.buckets.map(_.value) should contain allOf (22L, 33L) } accumulator.add(fiveSecondsThree) shouldBe empty - for(_ <- 1 to 10) { + for (_ <- 1 to 10) { val peekSnapshot = accumulator.peek() val mergedHistogram = peekSnapshot.histograms.find(_.name == "histogram").get.instruments.head.value val mergedRangeSampler = peekSnapshot.rangeSamplers.find(_.name == "rangeSampler").get.instruments.head.value peekSnapshot.counters.find(_.name == "counter").get.instruments.head.value shouldBe (67) peekSnapshot.gauges.find(_.name == "gauge").get.instruments.head.value shouldBe (12) - mergedHistogram.buckets.map(_.value) should contain allOf(22L, 33L, 12L) - mergedRangeSampler.buckets.map(_.value) should contain allOf(22L, 33L, 12L) + mergedHistogram.buckets.map(_.value) should contain allOf (22L, 33L, 12L) + mergedRangeSampler.buckets.map(_.value) should contain allOf (22L, 33L, 12L) } } @@ -151,10 +151,10 @@ class PeriodSnapshotAccumulatorSpec extends AnyWordSpec with Matchers with Recon val mergedHistogram = snapshotOne.histograms.find(_.name == "histogram").get.instruments.head.value val mergedRangeSampler = snapshotOne.rangeSamplers.find(_.name == "rangeSampler").get.instruments.head.value - snapshotOne.counters.find(_.name == "counter").get.instruments.head.value shouldBe(67) - snapshotOne.gauges.find(_.name == "gauge").get.instruments.head.value shouldBe(12) - mergedHistogram.buckets.map(_.value) should contain allOf(22L, 33L, 12L) - mergedRangeSampler.buckets.map(_.value) should contain allOf(22L, 33L, 12L) + snapshotOne.counters.find(_.name == "counter").get.instruments.head.value shouldBe (67) + snapshotOne.gauges.find(_.name == "gauge").get.instruments.head.value shouldBe (12) + mergedHistogram.buckets.map(_.value) should contain allOf (22L, 33L, 12L) + mergedRangeSampler.buckets.map(_.value) should contain allOf (22L, 33L, 12L) val emptySnapshot = accumulator.peek() emptySnapshot.histograms shouldBe empty @@ -192,7 +192,6 @@ class PeriodSnapshotAccumulatorSpec extends AnyWordSpec with Matchers with Recon val nineSeconds = createPeriodSnapshot(alignedZeroTime, alignedZeroTime.plusSeconds(9), 22) val tenSeconds = createPeriodSnapshot(alignedZeroTime, alignedZeroTime.plusSeconds(10), 36) - def newAccumulator(duration: Long, margin: Long) = PeriodSnapshot.accumulator(Duration.ofSeconds(duration), Duration.ofSeconds(margin)) @@ -201,15 +200,43 @@ class PeriodSnapshotAccumulatorSpec extends AnyWordSpec with Matchers with Recon */ def createPeriodSnapshot(from: Instant, to: Instant, value: Long): PeriodSnapshot = { val valueSettings = Metric.Settings.ForValueInstrument(MeasurementUnit.none, Duration.ofSeconds(10)) - val distributionSettings = Metric.Settings.ForDistributionInstrument(MeasurementUnit.none, Duration.ofSeconds(10), DynamicRange.Default) + val distributionSettings = + Metric.Settings.ForDistributionInstrument(MeasurementUnit.none, Duration.ofSeconds(10), DynamicRange.Default) val distribution = Kamon.histogram("temp").withoutTags().record(value).distribution() - PeriodSnapshot(from, to, - counters = Seq(MetricSnapshot.ofValues("counter", "", valueSettings, Seq(Instrument.Snapshot(TagSet.of("metric", "counter"), value)))), - gauges = Seq(MetricSnapshot.ofValues("gauge", "", valueSettings, Seq(Instrument.Snapshot(TagSet.of("metric", "gauge"), value)))), - histograms = Seq(MetricSnapshot.ofDistributions("histogram", "", distributionSettings, Seq(Instrument.Snapshot(TagSet.of("metric", "histogram"), distribution)))), - timers = Seq(MetricSnapshot.ofDistributions("timer", "", distributionSettings, Seq(Instrument.Snapshot(TagSet.of("metric", "timer"), distribution)))), - rangeSamplers = Seq(MetricSnapshot.ofDistributions("rangeSampler", "", distributionSettings, Seq(Instrument.Snapshot(TagSet.of("metric", "rangeSampler"), distribution)))) + PeriodSnapshot( + from, + to, + counters = Seq(MetricSnapshot.ofValues( + "counter", + "", + valueSettings, + Seq(Instrument.Snapshot(TagSet.of("metric", "counter"), value)) + )), + gauges = Seq(MetricSnapshot.ofValues( + "gauge", + "", + valueSettings, + Seq(Instrument.Snapshot(TagSet.of("metric", "gauge"), value)) + )), + histograms = Seq(MetricSnapshot.ofDistributions( + "histogram", + "", + distributionSettings, + Seq(Instrument.Snapshot(TagSet.of("metric", "histogram"), distribution)) + )), + timers = Seq(MetricSnapshot.ofDistributions( + "timer", + "", + distributionSettings, + Seq(Instrument.Snapshot(TagSet.of("metric", "timer"), distribution)) + )), + rangeSamplers = Seq(MetricSnapshot.ofDistributions( + "rangeSampler", + "", + distributionSettings, + Seq(Instrument.Snapshot(TagSet.of("metric", "rangeSampler"), distribution)) + )) ) } diff --git a/core/kamon-core-tests/src/test/scala/kamon/metric/RangeSamplerSpec.scala b/core/kamon-core-tests/src/test/scala/kamon/metric/RangeSamplerSpec.scala index 17e12f845..8cb469205 100644 --- a/core/kamon-core-tests/src/test/scala/kamon/metric/RangeSamplerSpec.scala +++ b/core/kamon-core-tests/src/test/scala/kamon/metric/RangeSamplerSpec.scala @@ -13,7 +13,6 @@ * ========================================================================================= */ - package kamon.metric import java.time.Duration @@ -24,7 +23,8 @@ import org.scalatest.wordspec.AnyWordSpec import scala.concurrent.duration.DurationInt -class RangeSamplerSpec extends AnyWordSpec with Matchers with InstrumentInspection.Syntax with InitAndStopKamonAfterAll { +class RangeSamplerSpec extends AnyWordSpec with Matchers with InstrumentInspection.Syntax + with InitAndStopKamonAfterAll { "a RangeSampler" should { "track ascending tendencies" in { diff --git a/core/kamon-core-tests/src/test/scala/kamon/metric/TimerSpec.scala b/core/kamon-core-tests/src/test/scala/kamon/metric/TimerSpec.scala index 3c0c06886..df8e7d7bc 100644 --- a/core/kamon-core-tests/src/test/scala/kamon/metric/TimerSpec.scala +++ b/core/kamon-core-tests/src/test/scala/kamon/metric/TimerSpec.scala @@ -20,7 +20,6 @@ import kamon.testkit.InstrumentInspection import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec - class TimerSpec extends AnyWordSpec with Matchers with InstrumentInspection.Syntax { "a Timer" should { @@ -43,7 +42,6 @@ class TimerSpec extends AnyWordSpec with Matchers with InstrumentInspection.Synt timer.distribution().count shouldBe 1 } - "allow to record values and produce distributions as Histograms do" in { val timer = Kamon.timer("test-timer").withoutTags() timer.record(100) @@ -66,4 +64,4 @@ class TimerSpec extends AnyWordSpec with Matchers with InstrumentInspection.Synt emptyDistribution.buckets.length shouldBe 0 } } -} \ No newline at end of file +} diff --git a/core/kamon-core-tests/src/test/scala/kamon/module/ModuleRegistrySpec.scala b/core/kamon-core-tests/src/test/scala/kamon/module/ModuleRegistrySpec.scala index d7a057236..a12c9beb3 100644 --- a/core/kamon-core-tests/src/test/scala/kamon/module/ModuleRegistrySpec.scala +++ b/core/kamon-core-tests/src/test/scala/kamon/module/ModuleRegistrySpec.scala @@ -29,7 +29,7 @@ import org.scalatest.wordspec.AnyWordSpec import scala.concurrent.Await import scala.concurrent.duration._ -class ModuleRegistrySpec extends AnyWordSpec with Matchers with Reconfigure with Eventually with BeforeAndAfterAll { +class ModuleRegistrySpec extends AnyWordSpec with Matchers with Reconfigure with Eventually with BeforeAndAfterAll { "The ModuleRegistry" when { "working with metrics reporters" should { "report all metrics if no filters are applied" in { @@ -42,7 +42,7 @@ class ModuleRegistrySpec extends AnyWordSpec with Matchers with Reconfigure with eventually { reporter.snapshotCount() should be >= 1 - reporter.metrics() should contain allOf( + reporter.metrics() should contain allOf ( "test.hello", "test.world", "other.hello" @@ -58,7 +58,8 @@ class ModuleRegistrySpec extends AnyWordSpec with Matchers with Reconfigure with Kamon.counter("other.hello").withoutTags().increment() val originalReporter = new SeenMetricsReporter() - val reporter = MetricReporter.withTransformations(originalReporter, MetricReporter.filterMetrics("does-not-exist")) + val reporter = + MetricReporter.withTransformations(originalReporter, MetricReporter.filterMetrics("does-not-exist")) val subscription = Kamon.registerModule("reporter-registry-spec", reporter) eventually { @@ -75,13 +76,13 @@ class ModuleRegistrySpec extends AnyWordSpec with Matchers with Reconfigure with Kamon.counter("other.hello").withoutTags().increment() val originalReporter = new SeenMetricsReporter() - val reporter = MetricReporter.withTransformations(originalReporter, MetricReporter.filterMetrics("test-metric-filter")) + val reporter = + MetricReporter.withTransformations(originalReporter, MetricReporter.filterMetrics("test-metric-filter")) val subscription = Kamon.registerModule("reporter-registry-spec", reporter) - eventually { originalReporter.snapshotCount() should be >= 1 - originalReporter.metrics() should contain allOf( + originalReporter.metrics() should contain allOf ( "test.hello", "test.world" ) @@ -102,7 +103,6 @@ class ModuleRegistrySpec extends AnyWordSpec with Matchers with Reconfigure with } } - override protected def beforeAll(): Unit = { Kamon.init() @@ -117,7 +117,6 @@ class ModuleRegistrySpec extends AnyWordSpec with Matchers with Reconfigure with ) } - override protected def afterAll(): Unit = { reset() Kamon.stop() diff --git a/core/kamon-core-tests/src/test/scala/kamon/status/EnvironmentSpec.scala b/core/kamon-core-tests/src/test/scala/kamon/status/EnvironmentSpec.scala index 5c8262678..b39837820 100644 --- a/core/kamon-core-tests/src/test/scala/kamon/status/EnvironmentSpec.scala +++ b/core/kamon-core-tests/src/test/scala/kamon/status/EnvironmentSpec.scala @@ -48,7 +48,8 @@ class EnvironmentSpec extends AnyWordSpec with Matchers { | host = spec-host | instance = spec-instance |} - """.stripMargin) + """.stripMargin + ) val env = Environment.from(customConfig.withFallback(baseConfig)) @@ -64,11 +65,12 @@ class EnvironmentSpec extends AnyWordSpec with Matchers { | custom1 = "test1" | env = staging |} - """.stripMargin) + """.stripMargin + ) val env = Environment.from(customConfig.withFallback(baseConfig)) - env.tags.toMap should contain allOf( + env.tags.toMap should contain allOf ( ("custom1" -> "test1"), ("env" -> "staging") ) diff --git a/core/kamon-core-tests/src/test/scala/kamon/tag/TagSetSpec.scala b/core/kamon-core-tests/src/test/scala/kamon/tag/TagSetSpec.scala index 9cdd339cb..bad771a66 100644 --- a/core/kamon-core-tests/src/test/scala/kamon/tag/TagSetSpec.scala +++ b/core/kamon-core-tests/src/test/scala/kamon/tag/TagSetSpec.scala @@ -177,15 +177,16 @@ class TagSetSpec extends AnyWordSpec with Matchers { } } - def matchPair(key: String, value: Any) = { tag: Tag => { - tag match { - case t: Tag.String => t.key == key && t.value == value - case t: Tag.Long => t.key == key && t.value == value - case t: Tag.Boolean => t.key == key && t.value == value - } - - }} + def matchPair(key: String, value: Any) = { tag: Tag => + { + tag match { + case t: Tag.String => t.key == key && t.value == value + case t: Tag.Long => t.key == key && t.value == value + case t: Tag.Boolean => t.key == key && t.value == value + } + } + } val NullString: java.lang.String = null val NullBoolean: java.lang.Boolean = null diff --git a/core/kamon-core-tests/src/test/scala/kamon/trace/B3SingleSpanPropagationSpec.scala b/core/kamon-core-tests/src/test/scala/kamon/trace/B3SingleSpanPropagationSpec.scala index 8494dc272..113084ef2 100644 --- a/core/kamon-core-tests/src/test/scala/kamon/trace/B3SingleSpanPropagationSpec.scala +++ b/core/kamon-core-tests/src/test/scala/kamon/trace/B3SingleSpanPropagationSpec.scala @@ -24,7 +24,6 @@ import org.scalatest.wordspec.AnyWordSpec import scala.collection.mutable - class B3SingleSpanPropagationSpec extends AnyWordSpec with Matchers with OptionValues { val b3SinglePropagation = SpanPropagation.B3Single() @@ -43,7 +42,6 @@ class B3SingleSpanPropagationSpec extends AnyWordSpec with Matchers with OptionV headersMap.get("B3").value shouldBe "1234-4321-1" } - "not inject anything if there is no Span in the Context" in { val headersMap = mutable.Map.empty[String, String] b3SinglePropagation.write(Context.Empty, headerWriterFromMap(headersMap)) @@ -82,10 +80,14 @@ class B3SingleSpanPropagationSpec extends AnyWordSpec with Matchers with OptionV "not include the X-B3-Sampled header if the sampling decision is unknown" in { val context = testContext() val sampledSpan = context.get(Span.Key) - val notSampledSpanContext = Context.Empty.withEntry(Span.Key, - new Span.Remote(sampledSpan.id, sampledSpan.parentId, Trace(sampledSpan.trace.id, SamplingDecision.DoNotSample))) - val unknownSamplingSpanContext = Context.Empty.withEntry(Span.Key, - new Span.Remote(sampledSpan.id, sampledSpan.parentId, Trace(sampledSpan.trace.id, SamplingDecision.Unknown))) + val notSampledSpanContext = Context.Empty.withEntry( + Span.Key, + new Span.Remote(sampledSpan.id, sampledSpan.parentId, Trace(sampledSpan.trace.id, SamplingDecision.DoNotSample)) + ) + val unknownSamplingSpanContext = Context.Empty.withEntry( + Span.Key, + new Span.Remote(sampledSpan.id, sampledSpan.parentId, Trace(sampledSpan.trace.id, SamplingDecision.Unknown)) + ) val headersMap = mutable.Map.empty[String, String] @@ -97,7 +99,7 @@ class B3SingleSpanPropagationSpec extends AnyWordSpec with Matchers with OptionV headersMap.get("B3").value shouldBe "1234-4321-0-2222" headersMap.clear() - b3SinglePropagation.write(unknownSamplingSpanContext,headerWriterFromMap(headersMap)) + b3SinglePropagation.write(unknownSamplingSpanContext, headerWriterFromMap(headersMap)) headersMap.get("B3").value shouldBe "1234-4321-2222" headersMap.clear() } @@ -148,7 +150,7 @@ class B3SingleSpanPropagationSpec extends AnyWordSpec with Matchers with OptionV def headerReaderFromMap(map: Map[String, String]): HttpPropagation.HeaderReader = new HttpPropagation.HeaderReader { override def read(header: String): Option[String] = { - if(map.get("fail").nonEmpty) + if (map.get("fail").nonEmpty) sys.error("failing on purpose") map.get(header) @@ -157,27 +159,34 @@ class B3SingleSpanPropagationSpec extends AnyWordSpec with Matchers with OptionV override def readAll(): Map[String, String] = map } - def headerWriterFromMap(map: mutable.Map[String, String]): HttpPropagation.HeaderWriter = new HttpPropagation.HeaderWriter { - override def write(header: String, value: String): Unit = map.put(header, value) - } + def headerWriterFromMap(map: mutable.Map[String, String]): HttpPropagation.HeaderWriter = + new HttpPropagation.HeaderWriter { + override def write(header: String, value: String): Unit = map.put(header, value) + } def testContext(): Context = - Context.of(Span.Key, new Span.Remote( - id = Identifier("4321", Array[Byte](4, 3, 2, 1)), - parentId = Identifier("2222", Array[Byte](2, 2, 2, 2)), - trace = Trace( - id = Identifier("1234", Array[Byte](1, 2, 3, 4)), - samplingDecision = SamplingDecision.Sample + Context.of( + Span.Key, + new Span.Remote( + id = Identifier("4321", Array[Byte](4, 3, 2, 1)), + parentId = Identifier("2222", Array[Byte](2, 2, 2, 2)), + trace = Trace( + id = Identifier("1234", Array[Byte](1, 2, 3, 4)), + samplingDecision = SamplingDecision.Sample + ) ) - )) + ) def testContextWithoutParent(): Context = - Context.of(Span.Key, new Span.Remote( - id = Identifier("4321", Array[Byte](4, 3, 2, 1)), - parentId = Identifier.Empty, - trace = Trace( - id = Identifier("1234", Array[Byte](1, 2, 3, 4)), - samplingDecision = SamplingDecision.Sample + Context.of( + Span.Key, + new Span.Remote( + id = Identifier("4321", Array[Byte](4, 3, 2, 1)), + parentId = Identifier.Empty, + trace = Trace( + id = Identifier("1234", Array[Byte](1, 2, 3, 4)), + samplingDecision = SamplingDecision.Sample + ) ) - )) + ) } diff --git a/core/kamon-core-tests/src/test/scala/kamon/trace/B3SpanPropagationSpec.scala b/core/kamon-core-tests/src/test/scala/kamon/trace/B3SpanPropagationSpec.scala index 937e1acbb..2d525c100 100644 --- a/core/kamon-core-tests/src/test/scala/kamon/trace/B3SpanPropagationSpec.scala +++ b/core/kamon-core-tests/src/test/scala/kamon/trace/B3SpanPropagationSpec.scala @@ -24,7 +24,6 @@ import org.scalatest.wordspec.AnyWordSpec import scala.collection.mutable - class B3SpanPropagationSpec extends AnyWordSpec with Matchers with OptionValues { val b3Propagation = SpanPropagation.B3() @@ -102,18 +101,22 @@ class B3SpanPropagationSpec extends AnyWordSpec with Matchers with OptionValues "not include the X-B3-Sampled header if the sampling decision is unknown" in { val context = testContext() val sampledSpan = context.get(Span.Key) - val notSampledSpanContext = Context.Empty.withEntry(Span.Key, - new Span.Remote(sampledSpan.id, sampledSpan.parentId, Trace(sampledSpan.trace.id, SamplingDecision.DoNotSample))) - val unknownSamplingSpanContext = Context.Empty.withEntry(Span.Key, - new Span.Remote(sampledSpan.id, sampledSpan.parentId, Trace(sampledSpan.trace.id, SamplingDecision.Unknown))) + val notSampledSpanContext = Context.Empty.withEntry( + Span.Key, + new Span.Remote(sampledSpan.id, sampledSpan.parentId, Trace(sampledSpan.trace.id, SamplingDecision.DoNotSample)) + ) + val unknownSamplingSpanContext = Context.Empty.withEntry( + Span.Key, + new Span.Remote(sampledSpan.id, sampledSpan.parentId, Trace(sampledSpan.trace.id, SamplingDecision.Unknown)) + ) val headersMap = mutable.Map.empty[String, String] b3Propagation.write(context, headerWriterFromMap(headersMap)) - headersMap.get("X-B3-Sampled").value shouldBe("1") + headersMap.get("X-B3-Sampled").value shouldBe ("1") headersMap.clear() b3Propagation.write(notSampledSpanContext, headerWriterFromMap(headersMap)) - headersMap.get("X-B3-Sampled").value shouldBe("0") + headersMap.get("X-B3-Sampled").value shouldBe ("0") headersMap.clear() b3Propagation.write(unknownSamplingSpanContext, headerWriterFromMap(headersMap)) @@ -221,13 +224,13 @@ class B3SpanPropagationSpec extends AnyWordSpec with Matchers with OptionValues val writenHeaders = mutable.Map.empty[String, String] val context = b3Propagation.read(headerReaderFromMap(headers), Context.Empty) b3Propagation.write(context, headerWriterFromMap(writenHeaders)) - writenHeaders should contain theSameElementsAs(headers) + writenHeaders should contain theSameElementsAs (headers) } } def headerReaderFromMap(map: Map[String, String]): HttpPropagation.HeaderReader = new HttpPropagation.HeaderReader { override def read(header: String): Option[String] = { - if(map.get("fail").nonEmpty) + if (map.get("fail").nonEmpty) sys.error("failing on purpose") map.get(header) @@ -236,28 +239,35 @@ class B3SpanPropagationSpec extends AnyWordSpec with Matchers with OptionValues override def readAll(): Map[String, String] = map } - def headerWriterFromMap(map: mutable.Map[String, String]): HttpPropagation.HeaderWriter = new HttpPropagation.HeaderWriter { - override def write(header: String, value: String): Unit = map.put(header, value) - } + def headerWriterFromMap(map: mutable.Map[String, String]): HttpPropagation.HeaderWriter = + new HttpPropagation.HeaderWriter { + override def write(header: String, value: String): Unit = map.put(header, value) + } def testContext(): Context = - Context.of(Span.Key, new Span.Remote( - id = Identifier("4321", Array[Byte](4, 3, 2, 1)), - parentId = Identifier("2222", Array[Byte](2, 2, 2, 2)), - trace = Trace( - id = Identifier("1234", Array[Byte](1, 2, 3, 4)), - samplingDecision = SamplingDecision.Sample + Context.of( + Span.Key, + new Span.Remote( + id = Identifier("4321", Array[Byte](4, 3, 2, 1)), + parentId = Identifier("2222", Array[Byte](2, 2, 2, 2)), + trace = Trace( + id = Identifier("1234", Array[Byte](1, 2, 3, 4)), + samplingDecision = SamplingDecision.Sample + ) ) - )) + ) def testContextWithoutParent(): Context = - Context.of(Span.Key, new Span.Remote( - id = Identifier("4321", Array[Byte](4, 3, 2, 1)), - parentId = Identifier.Empty, - trace = Trace( - id = Identifier("1234", Array[Byte](1, 2, 3, 4)), - samplingDecision = SamplingDecision.Sample + Context.of( + Span.Key, + new Span.Remote( + id = Identifier("4321", Array[Byte](4, 3, 2, 1)), + parentId = Identifier.Empty, + trace = Trace( + id = Identifier("1234", Array[Byte](1, 2, 3, 4)), + samplingDecision = SamplingDecision.Sample + ) ) - )) + ) -} \ No newline at end of file +} diff --git a/core/kamon-core-tests/src/test/scala/kamon/trace/DataDogSpanPropagationSpec.scala b/core/kamon-core-tests/src/test/scala/kamon/trace/DataDogSpanPropagationSpec.scala index 3cfb1682f..f34c8a08c 100644 --- a/core/kamon-core-tests/src/test/scala/kamon/trace/DataDogSpanPropagationSpec.scala +++ b/core/kamon-core-tests/src/test/scala/kamon/trace/DataDogSpanPropagationSpec.scala @@ -73,18 +73,22 @@ class DataDogSpanPropagationSpec extends AnyWordSpec with Matchers with OptionVa "not include the x-datadog-sampling-priority header if the sampling decision is unknown" in { val context = testContext() val sampledSpan = context.get(Span.Key) - val notSampledSpanContext = Context.Empty.withEntry(Span.Key, - new Span.Remote(sampledSpan.id, sampledSpan.parentId, Trace(sampledSpan.trace.id, SamplingDecision.DoNotSample))) - val unknownSamplingSpanContext = Context.Empty.withEntry(Span.Key, - new Span.Remote(sampledSpan.id, sampledSpan.parentId, Trace(sampledSpan.trace.id, SamplingDecision.Unknown))) + val notSampledSpanContext = Context.Empty.withEntry( + Span.Key, + new Span.Remote(sampledSpan.id, sampledSpan.parentId, Trace(sampledSpan.trace.id, SamplingDecision.DoNotSample)) + ) + val unknownSamplingSpanContext = Context.Empty.withEntry( + Span.Key, + new Span.Remote(sampledSpan.id, sampledSpan.parentId, Trace(sampledSpan.trace.id, SamplingDecision.Unknown)) + ) val headersMap = mutable.Map.empty[String, String] dataDogPropagation.write(context, headerWriterFromMap(headersMap)) - headersMap.get("x-datadog-sampling-priority").value shouldBe("1") + headersMap.get("x-datadog-sampling-priority").value shouldBe ("1") headersMap.clear() dataDogPropagation.write(notSampledSpanContext, headerWriterFromMap(headersMap)) - headersMap.get("x-datadog-sampling-priority").value shouldBe("0") + headersMap.get("x-datadog-sampling-priority").value shouldBe ("0") headersMap.clear() dataDogPropagation.write(unknownSamplingSpanContext, headerWriterFromMap(headersMap)) @@ -114,28 +118,27 @@ class DataDogSpanPropagationSpec extends AnyWordSpec with Matchers with OptionVa val writenHeaders = mutable.Map.empty[String, String] val context = dataDogPropagation.read(headerReaderFromMap(headers), Context.Empty) dataDogPropagation.write(context, headerWriterFromMap(writenHeaders)) - writenHeaders should contain theSameElementsAs(headers) + writenHeaders should contain theSameElementsAs (headers) } } - "SpanPropagation.DataDog.decodeUnsignedLongToHex" should { "decode unsigned long to expected hex value " in { - val expectedHex1 = "0"; - val actualHex1 = SpanPropagation.DataDog.decodeUnsignedLongToHex("0"); - expectedHex1 shouldBe actualHex1; + val expectedHex1 = "0"; + val actualHex1 = SpanPropagation.DataDog.decodeUnsignedLongToHex("0"); + expectedHex1 shouldBe actualHex1; - val expectedHex2 = "ff"; - val actualHex2 = SpanPropagation.DataDog.decodeUnsignedLongToHex("255"); - expectedHex2 shouldBe actualHex2; + val expectedHex2 = "ff"; + val actualHex2 = SpanPropagation.DataDog.decodeUnsignedLongToHex("255"); + expectedHex2 shouldBe actualHex2; - val expectedHex3 = "c5863f7d672b65bf"; - val actualHex3 = SpanPropagation.DataDog.decodeUnsignedLongToHex("14233133480185390527"); - expectedHex3 shouldBe actualHex3; + val expectedHex3 = "c5863f7d672b65bf"; + val actualHex3 = SpanPropagation.DataDog.decodeUnsignedLongToHex("14233133480185390527"); + expectedHex3 shouldBe actualHex3; - val expectedHex4 = "ffffffffffffffff"; - val actualHex4 = SpanPropagation.DataDog.decodeUnsignedLongToHex("18446744073709551615"); - expectedHex4 shouldBe actualHex4; + val expectedHex4 = "ffffffffffffffff"; + val actualHex4 = SpanPropagation.DataDog.decodeUnsignedLongToHex("18446744073709551615"); + expectedHex4 shouldBe actualHex4; } } @@ -144,7 +147,7 @@ class DataDogSpanPropagationSpec extends AnyWordSpec with Matchers with OptionVa def headerReaderFromMap(map: Map[String, String]): HttpPropagation.HeaderReader = new HttpPropagation.HeaderReader { override def read(header: String): Option[String] = { - if(map.get("fail").nonEmpty) + if (map.get("fail").nonEmpty) sys.error("failing on purpose") map.get(header) @@ -153,27 +156,34 @@ class DataDogSpanPropagationSpec extends AnyWordSpec with Matchers with OptionVa override def readAll(): Map[String, String] = map } - def headerWriterFromMap(map: mutable.Map[String, String]): HttpPropagation.HeaderWriter = new HttpPropagation.HeaderWriter { - override def write(header: String, value: String): Unit = map.put(header, value) - } + def headerWriterFromMap(map: mutable.Map[String, String]): HttpPropagation.HeaderWriter = + new HttpPropagation.HeaderWriter { + override def write(header: String, value: String): Unit = map.put(header, value) + } def testContext(): Context = - Context.of(Span.Key, new Span.Remote( - id = Identifier("4321", Array[Byte](4, 3, 2, 1)), - parentId = Identifier("2222", Array[Byte](2, 2, 2, 2)), - trace = Trace( - id = Identifier("1234", Array[Byte](1, 2, 3, 4)), - samplingDecision = SamplingDecision.Sample + Context.of( + Span.Key, + new Span.Remote( + id = Identifier("4321", Array[Byte](4, 3, 2, 1)), + parentId = Identifier("2222", Array[Byte](2, 2, 2, 2)), + trace = Trace( + id = Identifier("1234", Array[Byte](1, 2, 3, 4)), + samplingDecision = SamplingDecision.Sample + ) ) - )) + ) def testContextWithoutParent(): Context = - Context.of(Span.Key, new Span.Remote( - id = Identifier("4321", Array[Byte](4, 3, 2, 1)), - parentId = Identifier.Empty, - trace = Trace( - id = Identifier("1234", Array[Byte](1, 2, 3, 4)), - samplingDecision = SamplingDecision.Sample + Context.of( + Span.Key, + new Span.Remote( + id = Identifier("4321", Array[Byte](4, 3, 2, 1)), + parentId = Identifier.Empty, + trace = Trace( + id = Identifier("1234", Array[Byte](1, 2, 3, 4)), + samplingDecision = SamplingDecision.Sample + ) ) - )) + ) } diff --git a/core/kamon-core-tests/src/test/scala/kamon/trace/LocalSpanSpec.scala b/core/kamon-core-tests/src/test/scala/kamon/trace/LocalSpanSpec.scala index 23ffa9992..489c36801 100644 --- a/core/kamon-core-tests/src/test/scala/kamon/trace/LocalSpanSpec.scala +++ b/core/kamon-core-tests/src/test/scala/kamon/trace/LocalSpanSpec.scala @@ -24,7 +24,8 @@ import org.scalatest.OptionValues import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec -class LocalSpanSpec extends AnyWordSpec with Matchers with OptionValues with SpanInspection.Syntax with InitAndStopKamonAfterAll { +class LocalSpanSpec extends AnyWordSpec with Matchers with OptionValues with SpanInspection.Syntax + with InitAndStopKamonAfterAll { "a real span" when { "sampled and finished" should { @@ -36,7 +37,7 @@ class LocalSpanSpec extends AnyWordSpec with Matchers with OptionValues with Spa .start(Instant.EPOCH.plusSeconds(1)) .toFinished(Instant.EPOCH.plusSeconds(10)) - finishedSpan.operationName shouldBe("test-span") + finishedSpan.operationName shouldBe ("test-span") finishedSpan.from shouldBe Instant.EPOCH.plusSeconds(1) finishedSpan.to shouldBe Instant.EPOCH.plusSeconds(10) finishedSpan.tags.get(any("test")) shouldBe "value" @@ -47,17 +48,17 @@ class LocalSpanSpec extends AnyWordSpec with Matchers with OptionValues with Spa val linkedSpan = Kamon.spanBuilder("linked").start() val finishedSpan = Kamon.spanBuilder("full-span") - .tag("builder-string-tag", "value") - .tag("builder-boolean-tag-true", true) - .tag("builder-boolean-tag-false", false) - .tag("builder-number-tag", 42) - .start(Instant.EPOCH.plusSeconds(1)) - .tag("span-string-tag", "value") - .tag("span-boolean-tag-true", true) - .tag("span-boolean-tag-false", false) - .tag("span-number-tag", 42) - .mark("my-mark") - .mark("my-custom-timetamp-mark", Instant.EPOCH.plusSeconds(4)) + .tag("builder-string-tag", "value") + .tag("builder-boolean-tag-true", true) + .tag("builder-boolean-tag-false", false) + .tag("builder-number-tag", 42) + .start(Instant.EPOCH.plusSeconds(1)) + .tag("span-string-tag", "value") + .tag("span-boolean-tag-true", true) + .tag("span-boolean-tag-false", false) + .tag("span-number-tag", 42) + .mark("my-mark") + .mark("my-custom-timetamp-mark", Instant.EPOCH.plusSeconds(4)) .link(linkedSpan, Span.Link.Kind.FollowsFrom) .name("fully-populated-span") .toFinished(Instant.EPOCH.plusSeconds(10)) @@ -73,12 +74,12 @@ class LocalSpanSpec extends AnyWordSpec with Matchers with OptionValues with Spa finishedSpan.tags.get(plainBoolean("span-boolean-tag-false")) shouldBe false finishedSpan.tags.get(plainLong("builder-number-tag")) shouldBe 42L finishedSpan.tags.get(plainLong("span-number-tag")) shouldBe 42L - finishedSpan.marks.map(_.key) should contain allOf( + finishedSpan.marks.map(_.key) should contain allOf ( "my-mark", "my-custom-timetamp-mark" ) - finishedSpan.links should contain only( + finishedSpan.links should contain only ( Span.Link(Kind.FollowsFrom, linkedSpan.trace, linkedSpan.id) ) diff --git a/core/kamon-core-tests/src/test/scala/kamon/trace/LocalTailSamplerSpec.scala b/core/kamon-core-tests/src/test/scala/kamon/trace/LocalTailSamplerSpec.scala index b12ea385c..2275ce47d 100644 --- a/core/kamon-core-tests/src/test/scala/kamon/trace/LocalTailSamplerSpec.scala +++ b/core/kamon-core-tests/src/test/scala/kamon/trace/LocalTailSamplerSpec.scala @@ -26,11 +26,10 @@ import org.scalatest.wordspec.AnyWordSpec import java.time.Instant - -class LocalTailSamplerSpec extends AnyWordSpec with Matchers with OptionValues with SpanInspection.Syntax with Eventually +class LocalTailSamplerSpec extends AnyWordSpec with Matchers with OptionValues with SpanInspection.Syntax + with Eventually with SpanSugar with TestSpanReporter with Reconfigure with InitAndStopKamonAfterAll { - "the Kamon local tail sampler" should { "keep traces that match the error count threshold" in { applyConfig( @@ -44,7 +43,8 @@ class LocalTailSamplerSpec extends AnyWordSpec with Matchers with OptionValues w | error-count-threshold = 3 | } |} - |""".stripMargin) + |""".stripMargin + ) val parentSpan = Kamon.spanBuilder("parent-with-errors").start() @@ -79,7 +79,8 @@ class LocalTailSamplerSpec extends AnyWordSpec with Matchers with OptionValues w | latency-threshold = 3 seconds | } |} - |""".stripMargin) + |""".stripMargin + ) val startInstant = Instant.now() val parentSpan = Kamon.spanBuilder("parent-with-high-latency").start(startInstant) @@ -115,7 +116,8 @@ class LocalTailSamplerSpec extends AnyWordSpec with Matchers with OptionValues w | latency-threshold = 3 seconds | } |} - |""".stripMargin) + |""".stripMargin + ) val startInstant = Instant.now() val parentSpan = Kamon.spanBuilder("parent-with-disabled-tail-sampler").start(startInstant) diff --git a/core/kamon-core-tests/src/test/scala/kamon/trace/QuickSpanCreationSpec.scala b/core/kamon-core-tests/src/test/scala/kamon/trace/QuickSpanCreationSpec.scala index f49dba145..8e922f279 100644 --- a/core/kamon-core-tests/src/test/scala/kamon/trace/QuickSpanCreationSpec.scala +++ b/core/kamon-core-tests/src/test/scala/kamon/trace/QuickSpanCreationSpec.scala @@ -13,8 +13,9 @@ import java.util.concurrent.CompletableFuture import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.Future -class QuickSpanCreationSpec extends AnyWordSpec with Matchers with OptionValues with SpanInspection.Syntax with Eventually - with SpanSugar with TestSpanReporter with Reconfigure with InitAndStopKamonAfterAll { +class QuickSpanCreationSpec extends AnyWordSpec with Matchers with OptionValues with SpanInspection.Syntax + with Eventually + with SpanSugar with TestSpanReporter with Reconfigure with InitAndStopKamonAfterAll { import kamon.Kamon.{currentSpan, span} @@ -58,7 +59,7 @@ class QuickSpanCreationSpec extends AnyWordSpec with Matchers with OptionValues eventually(timeout(5 seconds)) { val reportedSpan = testSpanReporter().nextSpan().value reportedSpan.operationName shouldBe "finishSimpleSpanWithComponent" - reportedSpan.metricTags.get(any("component")) should be ("customComponentTag") + reportedSpan.metricTags.get(any("component")) should be("customComponentTag") } } diff --git a/core/kamon-core-tests/src/test/scala/kamon/trace/SamplerSpec.scala b/core/kamon-core-tests/src/test/scala/kamon/trace/SamplerSpec.scala index 4b304b6e4..84942ca64 100644 --- a/core/kamon-core-tests/src/test/scala/kamon/trace/SamplerSpec.scala +++ b/core/kamon-core-tests/src/test/scala/kamon/trace/SamplerSpec.scala @@ -257,7 +257,7 @@ class SamplerSpec extends AnyWordSpec with Matchers with BeforeAndAfterEach { resetCounters() def simulate(duration: Duration)(perSecond: => Unit)(implicit sampler: AdaptiveSampler): Unit = { - duration.toSeconds.toInt.times{ + duration.toSeconds.toInt.times { perSecond sampler.adapt() } diff --git a/core/kamon-core-tests/src/test/scala/kamon/trace/SingleLengthIdentifierSchemeSpec.scala b/core/kamon-core-tests/src/test/scala/kamon/trace/SingleLengthIdentifierSchemeSpec.scala index bb6db7986..a9c438023 100644 --- a/core/kamon-core-tests/src/test/scala/kamon/trace/SingleLengthIdentifierSchemeSpec.scala +++ b/core/kamon-core-tests/src/test/scala/kamon/trace/SingleLengthIdentifierSchemeSpec.scala @@ -57,8 +57,8 @@ class SingleLengthIdentifierSchemeSpec extends AnyWordSpec with Matchers with Op } "return IdentityProvider.NoIdentifier if the provided input cannot be decoded into a Identifier" in { - factory.from("zzzz") shouldBe(Identifier.Empty) - factory.from(Array[Byte](1)) shouldBe(Identifier.Empty) + factory.from("zzzz") shouldBe (Identifier.Empty) + factory.from(Array[Byte](1)) shouldBe (Identifier.Empty) } } } diff --git a/core/kamon-core-tests/src/test/scala/kamon/trace/SpanMetricsSpec.scala b/core/kamon-core-tests/src/test/scala/kamon/trace/SpanMetricsSpec.scala index 05747e1cf..95fc0b493 100644 --- a/core/kamon-core-tests/src/test/scala/kamon/trace/SpanMetricsSpec.scala +++ b/core/kamon-core-tests/src/test/scala/kamon/trace/SpanMetricsSpec.scala @@ -130,10 +130,12 @@ class SpanMetricsSpec extends AnyWordSpec with Matchers with InstrumentInspectio .fail("Terrible Error with Throwable", new Throwable with NoStackTrace) .finish() - val histogram = Span.Metrics.ProcessingTime.withTags(TagSet.from(Map(operationTag, noErrorTag, parentOperationTag))) + val histogram = + Span.Metrics.ProcessingTime.withTags(TagSet.from(Map(operationTag, noErrorTag, parentOperationTag))) histogram.distribution().count shouldBe 1 - val errorHistogram = Span.Metrics.ProcessingTime.withTags(TagSet.from(Map(operationTag, errorTag, parentOperationTag))) + val errorHistogram = + Span.Metrics.ProcessingTime.withTags(TagSet.from(Map(operationTag, errorTag, parentOperationTag))) errorHistogram.distribution().count shouldBe 2 } @@ -161,10 +163,12 @@ class SpanMetricsSpec extends AnyWordSpec with Matchers with InstrumentInspectio .fail("Terrible Error with Throwable", new Throwable with NoStackTrace) .finish() - val histogram = Span.Metrics.ProcessingTime.withTags(TagSet.from(Map(operationTag, noErrorTag, parentOperationTag))) + val histogram = + Span.Metrics.ProcessingTime.withTags(TagSet.from(Map(operationTag, noErrorTag, parentOperationTag))) histogram.distribution().count shouldBe 0 - val errorHistogram = Span.Metrics.ProcessingTime.withTags(TagSet.from(Map(operationTag, errorTag, parentOperationTag))) + val errorHistogram = + Span.Metrics.ProcessingTime.withTags(TagSet.from(Map(operationTag, errorTag, parentOperationTag))) errorHistogram.distribution().count shouldBe 0 } @@ -180,7 +184,8 @@ class SpanMetricsSpec extends AnyWordSpec with Matchers with InstrumentInspectio val waitTime = Span.Metrics.WaitTime.withTags(TagSet.from(Map(operationTag, noErrorTag))).distribution() val elapsedTime = Span.Metrics.ElapsedTime.withTags(TagSet.from(Map(operationTag, noErrorTag))).distribution() - val processingTime = Span.Metrics.ProcessingTime.withTags(TagSet.from(Map(operationTag, noErrorTag))).distribution() + val processingTime = + Span.Metrics.ProcessingTime.withTags(TagSet.from(Map(operationTag, noErrorTag))).distribution() waitTime.count shouldBe 1 waitTime.buckets.head.value shouldBe 10 @@ -226,5 +231,3 @@ class SpanMetricsSpec extends AnyWordSpec with Matchers with InstrumentInspectio evaluated } } - - diff --git a/core/kamon-core-tests/src/test/scala/kamon/trace/SpanReportingDelaySpec.scala b/core/kamon-core-tests/src/test/scala/kamon/trace/SpanReportingDelaySpec.scala index 63138711f..07cb15235 100644 --- a/core/kamon-core-tests/src/test/scala/kamon/trace/SpanReportingDelaySpec.scala +++ b/core/kamon-core-tests/src/test/scala/kamon/trace/SpanReportingDelaySpec.scala @@ -24,8 +24,8 @@ import org.scalatest.matchers.should.Matchers import org.scalatest.time.SpanSugar import org.scalatest.wordspec.AnyWordSpec - -class SpanReportingDelaySpec extends AnyWordSpec with Matchers with OptionValues with SpanInspection.Syntax with Eventually +class SpanReportingDelaySpec extends AnyWordSpec with Matchers with OptionValues with SpanInspection.Syntax + with Eventually with SpanSugar with TestSpanReporter with Reconfigure with InitAndStopKamonAfterAll { "the Kamon tracer" when { diff --git a/core/kamon-core-tests/src/test/scala/kamon/trace/TracerSpec.scala b/core/kamon-core-tests/src/test/scala/kamon/trace/TracerSpec.scala index 2ccb4566c..af1fb68cf 100644 --- a/core/kamon-core-tests/src/test/scala/kamon/trace/TracerSpec.scala +++ b/core/kamon-core-tests/src/test/scala/kamon/trace/TracerSpec.scala @@ -27,7 +27,8 @@ import org.scalatest.OptionValues import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec -class TracerSpec extends AnyWordSpec with Matchers with SpanInspection.Syntax with OptionValues with InitAndStopKamonAfterAll { +class TracerSpec extends AnyWordSpec with Matchers with SpanInspection.Syntax with OptionValues + with InitAndStopKamonAfterAll { "the Kamon tracer" should { "construct a minimal Span that only has a operation name and default metric tags" in { @@ -103,10 +104,10 @@ class TracerSpec extends AnyWordSpec with Matchers with SpanInspection.Syntax wi val notSampledRemoteParent = remoteSpan(SamplingDecision.DoNotSample) Kamon.spanBuilder("childOfSampled").asChildOf(sampledRemoteParent).start().trace - .samplingDecision shouldBe(SamplingDecision.Sample) + .samplingDecision shouldBe (SamplingDecision.Sample) Kamon.spanBuilder("childOfNotSampled").asChildOf(notSampledRemoteParent).start().trace - .samplingDecision shouldBe(SamplingDecision.DoNotSample) + .samplingDecision shouldBe (SamplingDecision.DoNotSample) } "take a sampling decision if the parent's decision is unknown" in { @@ -114,7 +115,7 @@ class TracerSpec extends AnyWordSpec with Matchers with SpanInspection.Syntax wi val unknownSamplingRemoteParent = remoteSpan(SamplingDecision.Unknown) Kamon.spanBuilder("childOfSampled").asChildOf(unknownSamplingRemoteParent).start().trace - .samplingDecision shouldBe(SamplingDecision.Sample) + .samplingDecision shouldBe (SamplingDecision.Sample) Reconfigure.reset() } @@ -122,9 +123,9 @@ class TracerSpec extends AnyWordSpec with Matchers with SpanInspection.Syntax wi "never sample ignored operations" in { Reconfigure.sampleAlways() - Kamon.spanBuilder("/ready").start().trace.samplingDecision shouldBe(SamplingDecision.DoNotSample) - Kamon.spanBuilder("/status").start().trace.samplingDecision shouldBe(SamplingDecision.DoNotSample) - Kamon.spanBuilder("/other").start().trace.samplingDecision shouldBe(SamplingDecision.Sample) + Kamon.spanBuilder("/ready").start().trace.samplingDecision shouldBe (SamplingDecision.DoNotSample) + Kamon.spanBuilder("/status").start().trace.samplingDecision shouldBe (SamplingDecision.DoNotSample) + Kamon.spanBuilder("/other").start().trace.samplingDecision shouldBe (SamplingDecision.Sample) Reconfigure.reset() } @@ -192,7 +193,7 @@ class TracerSpec extends AnyWordSpec with Matchers with SpanInspection.Syntax wi Kamon.spanBuilder("suggestions") .asChildOf(remoteSpan(SamplingDecision.Unknown)) .start() - .trace.samplingDecision should not be(SamplingDecision.Unknown) + .trace.samplingDecision should not be (SamplingDecision.Unknown) } "not change a Spans sampling decision if they were created with Sample or DoNotSample decisions sampling decision" in { @@ -315,6 +316,10 @@ class TracerSpec extends AnyWordSpec with Matchers with SpanInspection.Syntax wi } private def remoteSpan(samplingDecision: SamplingDecision = SamplingDecision.Sample): Span.Remote = - Span.Remote(EightBytesIdentifier.generate(), EightBytesIdentifier.generate(), Trace(EightBytesIdentifier.generate(), samplingDecision)) + Span.Remote( + EightBytesIdentifier.generate(), + EightBytesIdentifier.generate(), + Trace(EightBytesIdentifier.generate(), samplingDecision) + ) } diff --git a/core/kamon-core-tests/src/test/scala/kamon/trace/UberSpanPropagationSpec.scala b/core/kamon-core-tests/src/test/scala/kamon/trace/UberSpanPropagationSpec.scala index f3f9c7190..5c334fbfd 100644 --- a/core/kamon-core-tests/src/test/scala/kamon/trace/UberSpanPropagationSpec.scala +++ b/core/kamon-core-tests/src/test/scala/kamon/trace/UberSpanPropagationSpec.scala @@ -24,7 +24,6 @@ import org.scalatest.wordspec.AnyWordSpec import scala.collection.mutable - class UberSpanPropagationSpec extends AnyWordSpec with Matchers with OptionValues { import SpanPropagation.Uber val uberPropagation = Uber() @@ -44,7 +43,6 @@ class UberSpanPropagationSpec extends AnyWordSpec with Matchers with OptionValue headersMap.get(Uber.HeaderName).value shouldBe "1234:4321:0:1" } - "not inject anything if there is no Span in the Context" in { val headersMap = mutable.Map.empty[String, String] uberPropagation.write(Context.Empty, headerWriterFromMap(headersMap)) @@ -83,10 +81,14 @@ class UberSpanPropagationSpec extends AnyWordSpec with Matchers with OptionValue "include the sampled header if the sampling decision is unknown" in { val context = testContext() val sampledSpan = context.get(Span.Key) - val notSampledSpanContext = Context.Empty.withEntry(Span.Key, - Span.Remote(sampledSpan.id, sampledSpan.parentId, Trace(sampledSpan.trace.id, SamplingDecision.DoNotSample))) - val unknownSamplingSpanContext = Context.Empty.withEntry(Span.Key, - Span.Remote(sampledSpan.id, sampledSpan.parentId, Trace(sampledSpan.trace.id, SamplingDecision.Unknown))) + val notSampledSpanContext = Context.Empty.withEntry( + Span.Key, + Span.Remote(sampledSpan.id, sampledSpan.parentId, Trace(sampledSpan.trace.id, SamplingDecision.DoNotSample)) + ) + val unknownSamplingSpanContext = Context.Empty.withEntry( + Span.Key, + Span.Remote(sampledSpan.id, sampledSpan.parentId, Trace(sampledSpan.trace.id, SamplingDecision.Unknown)) + ) val headersMap = mutable.Map.empty[String, String] @@ -98,7 +100,7 @@ class UberSpanPropagationSpec extends AnyWordSpec with Matchers with OptionValue headersMap.get(Uber.HeaderName).value shouldBe "1234:4321:2222:0" headersMap.clear() - uberPropagation.write(unknownSamplingSpanContext,headerWriterFromMap(headersMap)) + uberPropagation.write(unknownSamplingSpanContext, headerWriterFromMap(headersMap)) headersMap.get(Uber.HeaderName).value shouldBe "1234:4321:2222:0" headersMap.clear() } @@ -143,7 +145,9 @@ class UberSpanPropagationSpec extends AnyWordSpec with Matchers with OptionValue val writenHeaders = mutable.Map.empty[String, String] val context = uberPropagation.read(headerReaderFromMap(headers), Context.Empty) uberPropagation.write(context, headerWriterFromMap(writenHeaders)) - writenHeaders.map { case (k, v) => k -> SpanPropagation.Util.urlDecode(v) } should contain theSameElementsAs headers + writenHeaders.map { case (k, v) => + k -> SpanPropagation.Util.urlDecode(v) + } should contain theSameElementsAs headers } "extract a SpanContext from a URL-encoded header" in { @@ -159,7 +163,7 @@ class UberSpanPropagationSpec extends AnyWordSpec with Matchers with OptionValue def headerReaderFromMap(map: Map[String, String]): HttpPropagation.HeaderReader = new HttpPropagation.HeaderReader { override def read(header: String): Option[String] = { - if(map.get("fail").nonEmpty) + if (map.get("fail").nonEmpty) sys.error("failing on purpose") map.get(header) @@ -168,27 +172,34 @@ class UberSpanPropagationSpec extends AnyWordSpec with Matchers with OptionValue override def readAll(): Map[String, String] = map } - def headerWriterFromMap(map: mutable.Map[String, String]): HttpPropagation.HeaderWriter = new HttpPropagation.HeaderWriter { - override def write(header: String, value: String): Unit = map.put(header, value) - } + def headerWriterFromMap(map: mutable.Map[String, String]): HttpPropagation.HeaderWriter = + new HttpPropagation.HeaderWriter { + override def write(header: String, value: String): Unit = map.put(header, value) + } def testContext(): Context = - Context.of(Span.Key, new Span.Remote( - id = Identifier("4321", Array[Byte](4, 3, 2, 1)), - parentId = Identifier("2222", Array[Byte](2, 2, 2, 2)), - trace = Trace( - id = Identifier("1234", Array[Byte](1, 2, 3, 4)), - samplingDecision = SamplingDecision.Sample + Context.of( + Span.Key, + new Span.Remote( + id = Identifier("4321", Array[Byte](4, 3, 2, 1)), + parentId = Identifier("2222", Array[Byte](2, 2, 2, 2)), + trace = Trace( + id = Identifier("1234", Array[Byte](1, 2, 3, 4)), + samplingDecision = SamplingDecision.Sample + ) ) - )) + ) def testContextWithoutParent(): Context = - Context.of(Span.Key, new Span.Remote( - id = Identifier("4321", Array[Byte](4, 3, 2, 1)), - parentId = Identifier.Empty, - trace = Trace( - id = Identifier("1234", Array[Byte](1, 2, 3, 4)), - samplingDecision = SamplingDecision.Sample + Context.of( + Span.Key, + new Span.Remote( + id = Identifier("4321", Array[Byte](4, 3, 2, 1)), + parentId = Identifier.Empty, + trace = Trace( + id = Identifier("1234", Array[Byte](1, 2, 3, 4)), + samplingDecision = SamplingDecision.Sample + ) ) - )) + ) } diff --git a/core/kamon-core-tests/src/test/scala/kamon/trace/W3CTraceContextSpanPropagationSpec.scala b/core/kamon-core-tests/src/test/scala/kamon/trace/W3CTraceContextSpanPropagationSpec.scala index 7f4387960..fc884244a 100644 --- a/core/kamon-core-tests/src/test/scala/kamon/trace/W3CTraceContextSpanPropagationSpec.scala +++ b/core/kamon-core-tests/src/test/scala/kamon/trace/W3CTraceContextSpanPropagationSpec.scala @@ -39,13 +39,14 @@ class W3CTraceContextSpanPropagationSpec extends AnyWordSpec with Matchers with } } - def headerWriterFromMap(map: mutable.Map[String, String]): HttpPropagation.HeaderWriter = new HttpPropagation.HeaderWriter { - override def write(header: String, value: String): Unit = map.put(header, value) - } + def headerWriterFromMap(map: mutable.Map[String, String]): HttpPropagation.HeaderWriter = + new HttpPropagation.HeaderWriter { + override def write(header: String, value: String): Unit = map.put(header, value) + } def headerReaderFromMap(map: Map[String, String]): HttpPropagation.HeaderReader = new HttpPropagation.HeaderReader { override def read(header: String): Option[String] = { - if(map.contains("fail")) + if (map.contains("fail")) sys.error("failing on purpose") map.get(header) @@ -55,22 +56,28 @@ class W3CTraceContextSpanPropagationSpec extends AnyWordSpec with Matchers with } def testContext(): Context = - Context.of(Span.Key, Span.Remote( - id = Identifier("4321", Array[Byte](4, 3, 2, 1)), - parentId = Identifier("2222", Array[Byte](2, 2, 2, 2)), - trace = Trace( - id = Identifier("1234", Array[Byte](1, 2, 3, 4)), - samplingDecision = SamplingDecision.Sample + Context.of( + Span.Key, + Span.Remote( + id = Identifier("4321", Array[Byte](4, 3, 2, 1)), + parentId = Identifier("2222", Array[Byte](2, 2, 2, 2)), + trace = Trace( + id = Identifier("1234", Array[Byte](1, 2, 3, 4)), + samplingDecision = SamplingDecision.Sample + ) ) - )) + ) def testContextWithoutParent(): Context = - Context.of(Span.Key, Span.Remote( - id = Identifier("4321", Array[Byte](4, 3, 2, 1)), - parentId = Identifier.Empty, - trace = Trace( - id = Identifier("1234", Array[Byte](1, 2, 3, 4)), - samplingDecision = SamplingDecision.Sample + Context.of( + Span.Key, + Span.Remote( + id = Identifier("4321", Array[Byte](4, 3, 2, 1)), + parentId = Identifier.Empty, + trace = Trace( + id = Identifier("1234", Array[Byte](1, 2, 3, 4)), + samplingDecision = SamplingDecision.Sample + ) ) - )) + ) } diff --git a/core/kamon-core-tests/src/test/scala/kamon/util/ClockSpec.scala b/core/kamon-core-tests/src/test/scala/kamon/util/ClockSpec.scala index f31773dad..a75cbd7d3 100644 --- a/core/kamon-core-tests/src/test/scala/kamon/util/ClockSpec.scala +++ b/core/kamon-core-tests/src/test/scala/kamon/util/ClockSpec.scala @@ -20,16 +20,37 @@ class ClockSpec extends AnyWordSpec with Matchers { } "calculate nanos between two Instants" in { - Clock.nanosBetween(Instant.parse("2017-12-18T08:39:59.987654321Z"), Instant.parse("2017-12-18T08:39:59.987654322Z")) shouldBe 1 - Clock.nanosBetween(Instant.parse("2017-12-18T08:39:59.987654322Z"), Instant.parse("2017-12-18T08:39:59.987654321Z")) shouldBe -1 - Clock.nanosBetween(Instant.parse("2017-12-18T08:39:59.987Z"), Instant.parse("2017-12-18T08:39:59.988Z")) shouldBe 1000000 - Clock.nanosBetween(Instant.parse("2017-12-18T08:39:59.987654Z"), Instant.parse("2017-12-18T08:39:59.987Z")) shouldBe -654000 + Clock.nanosBetween( + Instant.parse("2017-12-18T08:39:59.987654321Z"), + Instant.parse("2017-12-18T08:39:59.987654322Z") + ) shouldBe 1 + Clock.nanosBetween( + Instant.parse("2017-12-18T08:39:59.987654322Z"), + Instant.parse("2017-12-18T08:39:59.987654321Z") + ) shouldBe -1 + Clock.nanosBetween( + Instant.parse("2017-12-18T08:39:59.987Z"), + Instant.parse("2017-12-18T08:39:59.988Z") + ) shouldBe 1000000 + Clock.nanosBetween( + Instant.parse("2017-12-18T08:39:59.987654Z"), + Instant.parse("2017-12-18T08:39:59.987Z") + ) shouldBe -654000 } "calculate ticks aligned to rounded boundaries" in { - Clock.nextAlignedInstant(Instant.parse("2017-12-18T08:39:59.999Z"), Duration.ofSeconds(10)).toString shouldBe "2017-12-18T08:40:00Z" - Clock.nextAlignedInstant(Instant.parse("2017-12-18T08:40:00.000Z"), Duration.ofSeconds(10)).toString shouldBe "2017-12-18T08:40:10Z" - Clock.nextAlignedInstant(Instant.parse("2017-12-18T08:39:14.906Z"), Duration.ofSeconds(10)).toString shouldBe "2017-12-18T08:39:20Z" + Clock.nextAlignedInstant( + Instant.parse("2017-12-18T08:39:59.999Z"), + Duration.ofSeconds(10) + ).toString shouldBe "2017-12-18T08:40:00Z" + Clock.nextAlignedInstant( + Instant.parse("2017-12-18T08:40:00.000Z"), + Duration.ofSeconds(10) + ).toString shouldBe "2017-12-18T08:40:10Z" + Clock.nextAlignedInstant( + Instant.parse("2017-12-18T08:39:14.906Z"), + Duration.ofSeconds(10) + ).toString shouldBe "2017-12-18T08:39:20Z" } } diff --git a/core/kamon-core-tests/src/test/scala/kamon/util/EnvironmentTagsSpec.scala b/core/kamon-core-tests/src/test/scala/kamon/util/EnvironmentTagsSpec.scala index c2c405f87..044cfc493 100644 --- a/core/kamon-core-tests/src/test/scala/kamon/util/EnvironmentTagsSpec.scala +++ b/core/kamon-core-tests/src/test/scala/kamon/util/EnvironmentTagsSpec.scala @@ -62,7 +62,8 @@ class EnvironmentTagsSpec extends AnyWordSpec with Matchers { |include-host = yes |include-instance = yes |exclude = [] - """.stripMargin) + """.stripMargin + ) val env = Kamon.environment val tags = EnvironmentTags.from(env, config) @@ -78,7 +79,8 @@ class EnvironmentTagsSpec extends AnyWordSpec with Matchers { |include-host = yes |include-instance = yes |exclude = [] - """.stripMargin) + """.stripMargin + ) val tags = EnvironmentTags.from(testEnv, config) tags("service") shouldBe testEnv.service @@ -109,7 +111,8 @@ class EnvironmentTagsSpec extends AnyWordSpec with Matchers { |include-host = yes |include-instance = yes |exclude = [ "region" ] - """.stripMargin) + """.stripMargin + ) val tags = EnvironmentTags.from(testEnv, config) tags("service") shouldBe testEnv.service @@ -135,7 +138,8 @@ class EnvironmentTagsSpec extends AnyWordSpec with Matchers { | "@tag-with-special-chars", | "\"tag-with-quotes\"" |] - """.stripMargin) + """.stripMargin + ) val tags = EnvironmentTags.from(testEnv, config) tags shouldBe empty diff --git a/core/kamon-core-tests/src/test/scala/kamon/util/ExponentiallyWeightedAverageSpec.scala b/core/kamon-core-tests/src/test/scala/kamon/util/ExponentiallyWeightedAverageSpec.scala index 7ab071d83..797bea135 100644 --- a/core/kamon-core-tests/src/test/scala/kamon/util/ExponentiallyWeightedAverageSpec.scala +++ b/core/kamon-core-tests/src/test/scala/kamon/util/ExponentiallyWeightedAverageSpec.scala @@ -6,23 +6,23 @@ import org.scalatest.matchers.should.Matchers import org.scalatest.time.SpanSugar import org.scalatest.wordspec.AnyWordSpec -class ExponentiallyWeightedAverageSpec extends AnyWordSpec with Matchers with Eventually with SpanSugar with TimesOnInt { +class ExponentiallyWeightedAverageSpec extends AnyWordSpec with Matchers with Eventually with SpanSugar + with TimesOnInt { "an Exponentially Weighted Moving Average" should { "converge to the actual average in few iterations from startup with the default weighting factor" in { val ewma = EWMA.create() - ewma.add(60D) - ewma.add(40D) - ewma.add(55D) - ewma.add(45D) - ewma.add(50D) - ewma.add(50D) - ewma.add(50D) - - ewma.average() shouldBe 50D +- 5D + ewma.add(60d) + ewma.add(40d) + ewma.add(55d) + ewma.add(45d) + ewma.add(50d) + ewma.add(50d) + ewma.add(50d) + + ewma.average() shouldBe 50d +- 5d } - "catch up with an up trend" in { val ewma = EWMA.create() var value = 500 @@ -32,24 +32,24 @@ class ExponentiallyWeightedAverageSpec extends AnyWordSpec with Matchers with Ev ewma.add(value) } - ewma.average() shouldBe value.toDouble +- 50D + ewma.average() shouldBe value.toDouble +- 50d } "take many iterations to converge on the average with a high weighting factor" in { - val ewma = EWMA.create(0.99D) - ewma.add(60D) - ewma.add(40D) - ewma.add(50D) - ewma.add(50D) - ewma.add(50D) + val ewma = EWMA.create(0.99d) + ewma.add(60d) + ewma.add(40d) + ewma.add(50d) + ewma.add(50d) + ewma.add(50d) 30 times { - ewma.add(50D) - ewma.add(50D) - ewma.add(50D) + ewma.add(50d) + ewma.add(50d) + ewma.add(50d) } - ewma.average() shouldBe 50D +- 5D + ewma.average() shouldBe 50d +- 5d } } diff --git a/core/kamon-core-tests/src/test/scala/kamon/util/FilterSpec.scala b/core/kamon-core-tests/src/test/scala/kamon/util/FilterSpec.scala index e62cf8e87..e2b8098ab 100644 --- a/core/kamon-core-tests/src/test/scala/kamon/util/FilterSpec.scala +++ b/core/kamon-core-tests/src/test/scala/kamon/util/FilterSpec.scala @@ -20,7 +20,6 @@ import kamon.Kamon import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec - class FilterSpec extends AnyWordSpec with Matchers { val testConfig = ConfigFactory.parseString( """ diff --git a/core/kamon-core/src/main/scala/kamon/Configuration.scala b/core/kamon-core/src/main/scala/kamon/Configuration.scala index 8df93360e..c9c4aa8d3 100644 --- a/core/kamon-core/src/main/scala/kamon/Configuration.scala +++ b/core/kamon-core/src/main/scala/kamon/Configuration.scala @@ -30,8 +30,8 @@ trait Configuration { private var _currentConfig: Config = loadInitialConfiguration() private var _onReconfigureHooks = Seq.empty[Configuration.OnReconfigureHook] @volatile private var _enabled: Boolean = _currentConfig.getBoolean(EnabledConfigurationName) - @volatile private var _shouldAttachInstrumentation: Boolean = _currentConfig.getBoolean(InitAttachInstrumentationConfigurationName) - + @volatile private var _shouldAttachInstrumentation: Boolean = + _currentConfig.getBoolean(InitAttachInstrumentationConfigurationName) /** * Retrieve Kamon's current configuration. @@ -42,7 +42,6 @@ trait Configuration { def enabled(): Boolean = _enabled - /** * Supply a new Config instance to rule Kamon's world. */ @@ -92,12 +91,16 @@ trait Configuration { try { val referenceConfig = ConfigFactory.defaultReference(ClassLoading.classLoader()) - err.println("Initializing Kamon with the reference configuration, none of the user settings will be in effect") + err.println( + "Initializing Kamon with the reference configuration, none of the user settings will be in effect" + ) referenceConfig } catch { case NonFatal(t) => - err.println("Kamon couldn't load the reference configuration settings from the reference.conf files due to: " + - t.getMessage + " at " + t.getStackTrace().mkString("", lineSeparator, lineSeparator)) + err.println( + "Kamon couldn't load the reference configuration settings from the reference.conf files due to: " + + t.getMessage + " at " + t.getStackTrace().mkString("", lineSeparator, lineSeparator) + ) ConfigFactory.empty() } diff --git a/core/kamon-core/src/main/scala/kamon/ContextPropagation.scala b/core/kamon-core/src/main/scala/kamon/ContextPropagation.scala index df5f0ef80..bf6bb240d 100644 --- a/core/kamon-core/src/main/scala/kamon/ContextPropagation.scala +++ b/core/kamon-core/src/main/scala/kamon/ContextPropagation.scala @@ -33,7 +33,6 @@ trait ContextPropagation { self: Configuration => init(self.config()) self.onReconfigure(newConfig => self.init(newConfig)) - /** * Retrieves the HTTP propagation channel with the supplied name. Propagation channels are configured on the * kamon.propagation.http configuration section. diff --git a/core/kamon-core/src/main/scala/kamon/ContextStorage.scala b/core/kamon-core/src/main/scala/kamon/ContextStorage.scala index fa6371195..34fd4c89b 100644 --- a/core/kamon-core/src/main/scala/kamon/ContextStorage.scala +++ b/core/kamon-core/src/main/scala/kamon/ContextStorage.scala @@ -86,7 +86,6 @@ trait ContextStorage { def runWithContextTag[T](key: String, value: String)(f: => T): T = runWithContext(currentContext().withTag(key, value))(f) - /** * Temporarily stores the provided Context tag on Kamon's Context Storage. The provided Context tag will be added to * the current Context and stored before executing the provided function, then removed right after execution @@ -95,7 +94,6 @@ trait ContextStorage { def runWithContextTag[T](key: String, value: Boolean)(f: => T): T = runWithContext(currentContext().withTag(key, value))(f) - /** * Temporarily stores the provided Context tag on Kamon's Context Storage. The provided Context tag will be added to * the current Context and stored before executing the provided function, then removed right after execution @@ -125,7 +123,7 @@ trait ContextStorage { throw t } finally { - if(finishSpan) + if (finishSpan) span.finish() } } @@ -147,10 +145,10 @@ object ContextStorage { Storage.Debug() else { storageTypeStr match { - case None => Storage.CrossThreadLocal() - case Some("debug") => Storage.Debug() + case None => Storage.CrossThreadLocal() + case Some("debug") => Storage.Debug() case Some("sameThreadScope") => Storage.ThreadLocal() - case Some("default") => Storage.CrossThreadLocal() + case Some("default") => Storage.CrossThreadLocal() case Some(other) => throw new IllegalArgumentException(s"Unrecognized kamon.context.storageType value: $other") } } diff --git a/core/kamon-core/src/main/scala/kamon/CurrentStatus.scala b/core/kamon-core/src/main/scala/kamon/CurrentStatus.scala index 52f37b1db..be5b012df 100644 --- a/core/kamon-core/src/main/scala/kamon/CurrentStatus.scala +++ b/core/kamon-core/src/main/scala/kamon/CurrentStatus.scala @@ -18,7 +18,6 @@ package kamon import kamon.status.{Environment, Status} - /** * Exposes access to the Kamon's current status. The status information contains details about the internal state of * several Kamon components and is exposed for the sole purpose of troubleshooting and debugging issues that might be @@ -26,11 +25,12 @@ import kamon.status.{Environment, Status} * * The Status APIs might change between minor versions. */ -trait CurrentStatus { self: ModuleManagement with Configuration with Utilities with Metrics with Tracing with ContextStorage => +trait CurrentStatus { + self: ModuleManagement with Configuration with Utilities with Metrics with Tracing with ContextStorage => @volatile private var _environment = Environment.from(self.config()) private val _status = new Status(self._moduleRegistry, self._metricRegistry, self) - onReconfigure(newConfig => _environment = Environment.from(newConfig) ) + onReconfigure(newConfig => _environment = Environment.from(newConfig)) /** * Returns the current enviroment instance constructed by Kamon using the "kamon.environment" settings. diff --git a/core/kamon-core/src/main/scala/kamon/Init.scala b/core/kamon-core/src/main/scala/kamon/Init.scala index af7e5b9d0..aeacf57b9 100644 --- a/core/kamon-core/src/main/scala/kamon/Init.scala +++ b/core/kamon-core/src/main/scala/kamon/Init.scala @@ -28,7 +28,9 @@ import scala.concurrent.Future * Provides APIs for handling common initialization tasks like starting modules, attaching instrumentation and * reconfiguring Kamon. */ -trait Init { self: ModuleManagement with Configuration with CurrentStatus with Metrics with Utilities with Tracing with ContextStorage => +trait Init { + self: ModuleManagement with Configuration with CurrentStatus with Metrics with Utilities with Tracing + with ContextStorage => private val _logger = LoggerFactory.getLogger(classOf[Init]) @volatile private var _scheduler: Option[ScheduledExecutorService] = None @@ -38,8 +40,8 @@ trait Init { self: ModuleManagement with Configuration with CurrentStatus with M * Attempts to attach the instrumentation agent and start all registered modules. */ def init(): Unit = { - if(enabled()) { - if(shouldAttachInstrumentation()) { + if (enabled()) { + if (shouldAttachInstrumentation()) { self.attachInstrumentation() } @@ -60,7 +62,7 @@ trait Init { self: ModuleManagement with Configuration with CurrentStatus with M def init(config: Config): Unit = { self.reconfigure(config) - if(enabled()) { + if (enabled()) { if (shouldAttachInstrumentation()) { self.attachInstrumentation() } @@ -80,7 +82,7 @@ trait Init { self: ModuleManagement with Configuration with CurrentStatus with M * Initializes Kamon without trying to attach the instrumentation agent from the Kamon Bundle. */ def initWithoutAttaching(): Unit = { - if(enabled()) { + if (enabled()) { self.initScheduler() self.loadModules() self.moduleRegistry().init() @@ -97,7 +99,7 @@ trait Init { self: ModuleManagement with Configuration with CurrentStatus with M def initWithoutAttaching(config: Config): Unit = { self.reconfigure(config) - if(enabled()) { + if (enabled()) { self.initWithoutAttaching() } else { self.disableInstrumentation() @@ -105,7 +107,6 @@ trait Init { self: ModuleManagement with Configuration with CurrentStatus with M } } - def stop(): Future[Unit] = { self.clearRegistry() self.stopScheduler() @@ -118,7 +119,7 @@ trait Init { self: ModuleManagement with Configuration with CurrentStatus with M * the Status module indicates that instrumentation has been already applied this method will not try to do anything. */ def attachInstrumentation(): Unit = { - if(!InstrumentationStatus.create(warnIfFailed = false).present) { + if (!InstrumentationStatus.create(warnIfFailed = false).present) { try { val attacherClass = Class.forName("kamon.runtime.Attacher") val attachMethod = attacherClass.getDeclaredMethod("attach") @@ -145,7 +146,7 @@ trait Init { self: ModuleManagement with Configuration with CurrentStatus with M val isEnabled = enabled() val showBanner = !config().getBoolean("kamon.init.hide-banner") - if(isEnabled) { + if (isEnabled) { val instrumentationStatus = status().instrumentation() val kanelaVersion = instrumentationStatus.kanelaVersion .map(v => green("v" + v)) @@ -167,8 +168,10 @@ trait Init { self: ModuleManagement with Configuration with CurrentStatus with M } else _logger.info(s"Initializing Kamon Telemetry v${BuildInfo.version} / Kanela ${kanelaVersion}") } else { - _logger.warn(s"Kamon is ${red("DISABLED")}. No instrumentation, reporters, or context propagation will be applied on this " + - "process. Restart the process with kamon.enabled=yes to restore Kamon's functionality") + _logger.warn( + s"Kamon is ${red("DISABLED")}. No instrumentation, reporters, or context propagation will be applied on this " + + "process. Restart the process with kamon.enabled=yes to restore Kamon's functionality" + ) } } @@ -187,7 +190,7 @@ trait Init { self: ModuleManagement with Configuration with CurrentStatus with M } catch { case _: ClassNotFoundException => - // Do nothing. This means that Kanela wasn't loaded so there was no need to do anything. + // Do nothing. This means that Kanela wasn't loaded so there was no need to do anything. case _: NoSuchMethodException => _logger.error("Failed to disable the Kanela instrumentation agent. Please ensure you are using Kanela >=1.0.17") diff --git a/core/kamon-core/src/main/scala/kamon/Kamon.scala b/core/kamon-core/src/main/scala/kamon/Kamon.scala index f255538b4..1c3d793c3 100644 --- a/core/kamon-core/src/main/scala/kamon/Kamon.scala +++ b/core/kamon-core/src/main/scala/kamon/Kamon.scala @@ -17,11 +17,11 @@ package kamon object Kamon extends Configuration - with Utilities - with Metrics - with Tracing - with ModuleManagement - with ContextPropagation - with ContextStorage - with CurrentStatus - with Init {} \ No newline at end of file + with Utilities + with Metrics + with Tracing + with ModuleManagement + with ContextPropagation + with ContextStorage + with CurrentStatus + with Init {} diff --git a/core/kamon-core/src/main/scala/kamon/ModuleManagement.scala b/core/kamon-core/src/main/scala/kamon/ModuleManagement.scala index 62bbf0ad0..00344361a 100644 --- a/core/kamon-core/src/main/scala/kamon/ModuleManagement.scala +++ b/core/kamon-core/src/main/scala/kamon/ModuleManagement.scala @@ -72,7 +72,6 @@ trait ModuleManagement { self: Configuration with Utilities with Metrics with Tr def registerModule(name: String, description: String, module: Module, configPath: String): Registration = _moduleRegistry.register(name, Some(description), module) - def addReporter(name: String, reporter: SpanReporter): Registration = _moduleRegistry.addReporter(name, None, reporter) @@ -88,7 +87,12 @@ trait ModuleManagement { self: Configuration with Utilities with Metrics with Tr def addReporter(name: String, description: String, reporter: MetricReporter, metricFilter: Filter): Registration = _moduleRegistry.addReporter(name, Option(description), reporter, Option(metricFilter)) - def addScheduledAction(name: String, description: Option[String], collector: ScheduledAction, interval: Duration): Registration = { + def addScheduledAction( + name: String, + description: Option[String], + collector: ScheduledAction, + interval: Duration + ): Registration = { _moduleRegistry.addScheduledAction(name, description, collector, interval) } diff --git a/core/kamon-core/src/main/scala/kamon/Tracing.scala b/core/kamon-core/src/main/scala/kamon/Tracing.scala index a7a0f5f48..3b1d24a31 100644 --- a/core/kamon-core/src/main/scala/kamon/Tracing.scala +++ b/core/kamon-core/src/main/scala/kamon/Tracing.scala @@ -32,14 +32,12 @@ trait Tracing { self: Configuration with Utilities with ContextStorage => private val _tracer = new Tracer(config(), clock(), self) onReconfigure(newConfig => _tracer.reconfigure(newConfig)) - /** * Returns the Identifier Scheme currently used by the tracer. */ def identifierScheme: Identifier.Scheme = _tracer.identifierScheme - /** * Creates a new SpanBuilder for a Server Span and applies the provided component name as a metric tag. It is * recommended that all Spans include a "component" metric tag that indicates what library or library section is @@ -48,7 +46,6 @@ trait Tracing { self: Configuration with Utilities with ContextStorage => def serverSpanBuilder(operationName: String, component: String): SpanBuilder = _tracer.serverSpanBuilder(operationName, component) - /** * Creates a new SpanBuilder for a Client Span and applies the provided component name as a metric tag. It is * recommended that all Spans include a "component" metric tag that indicates what library or library section is @@ -57,7 +54,6 @@ trait Tracing { self: Configuration with Utilities with ContextStorage => def clientSpanBuilder(operationName: String, component: String): SpanBuilder = _tracer.clientSpanBuilder(operationName, component) - /** * Creates a new SpanBuilder for a Producer Span and applies the provided component name as a metric tag. It is * recommended that all Spans include a "component" metric tag that indicates what library or library section is @@ -66,7 +62,6 @@ trait Tracing { self: Configuration with Utilities with ContextStorage => def producerSpanBuilder(operationName: String, component: String): SpanBuilder = _tracer.producerSpanBuilder(operationName, component) - /** * Creates a new SpanBuilder for a Consumer Span and applies the provided component name as a metric tag. It is * recommended that all Spans include a "component" metric tag that indicates what library or library section is @@ -75,7 +70,6 @@ trait Tracing { self: Configuration with Utilities with ContextStorage => def consumerSpanBuilder(operationName: String, component: String): SpanBuilder = _tracer.consumerSpanBuilder(operationName, component) - /** * Creates a new SpanBuilder for an Internal Span and applies the provided component name as a metric tag. It is * recommended that all Spans include a "component" metric tag that indicates what library or library section is @@ -84,14 +78,12 @@ trait Tracing { self: Configuration with Utilities with ContextStorage => def internalSpanBuilder(operationName: String, component: String): SpanBuilder = _tracer.internalSpanBuilder(operationName, component) - /** * Creates a new raw SpanBuilder instance using the provided operation name. */ def spanBuilder(operationName: String): SpanBuilder = _tracer.spanBuilder(operationName) - /** * Creates an Internal Span that finishes automatically when the provided function finishes execution. If the * provided function returns a scala.concurrent.Future or java.util.concurrent.CompletionStage implementation then @@ -112,7 +104,6 @@ trait Tracing { self: Configuration with Utilities with ContextStorage => def span[A](operationName: String)(f: => A): A = span(operationName, null)(f) - /** * Creates an Internal Span that finishes automatically when the provided function finishes execution. If the * provided function returns a scala.concurrent.Future or java.util.concurrent.CompletionStage implementation then @@ -165,7 +156,6 @@ trait Tracing { self: Configuration with Utilities with ContextStorage => } } - /** The Tracer instance is only exposed to other Kamon components that need it like the Module Registry and Status */ protected def tracer(): Tracer = _tracer diff --git a/core/kamon-core/src/main/scala/kamon/context/BinaryPropagation.scala b/core/kamon-core/src/main/scala/kamon/context/BinaryPropagation.scala index d3b33d1dc..f47854f03 100644 --- a/core/kamon-core/src/main/scala/kamon/context/BinaryPropagation.scala +++ b/core/kamon-core/src/main/scala/kamon/context/BinaryPropagation.scala @@ -20,7 +20,11 @@ package context import java.io.{ByteArrayInputStream, ByteArrayOutputStream, OutputStream} import com.typesafe.config.Config import kamon.context.generated.binary.context.{Context => ColferContext, Entry => ColferEntry, Tags => ColferTags} -import kamon.context.generated.binary.context.{BooleanTag => ColferBooleanTag, LongTag => ColferLongTag, StringTag => ColferStringTag} +import kamon.context.generated.binary.context.{ + BooleanTag => ColferBooleanTag, + LongTag => ColferLongTag, + StringTag => ColferStringTag +} import kamon.tag.{Tag, TagSet} import kamon.trace.Span.TagKeys import org.slf4j.LoggerFactory @@ -30,7 +34,6 @@ import scala.reflect.ClassTag import scala.util.control.NonFatal import scala.util.Try - /** * Context propagation that uses byte stream abstractions as the transport medium. The Binary propagation uses * instances of ByteStreamReader and ByteStreamWriter to decode and encode Context instances, respectively. @@ -46,6 +49,7 @@ object BinaryPropagation { * that wouldn't have a clearly defined behavior in the context of Context propagation. */ trait ByteStreamReader { + /** * Number of available bytes on the ByteStream. */ @@ -69,7 +73,6 @@ object BinaryPropagation { def readAll(): Array[Byte] } - object ByteStreamReader { /** @@ -84,7 +87,6 @@ object BinaryPropagation { } } - /** * Represents a writable stream of bytes. This interface closely resembles OutputStream, minus the functionality * that wouldn't have a clearly defined behavior in the context of Context propagation. @@ -139,8 +141,6 @@ object BinaryPropagation { } } - - /** * Create a new Binary Propagation instance from the provided configuration. */ @@ -164,15 +164,14 @@ object BinaryPropagation { } override def read(reader: ByteStreamReader): Context = { - if(reader.available() > 0) { + if (reader.available() > 0) { try { val colferContext = new ColferContext() colferContext.unmarshal(reader.readAll(), 0) - // Context tags val tagsBuilder = Map.newBuilder[String, Any] - if(colferContext.tags != null) { + if (colferContext.tags != null) { colferContext.tags.strings.foreach(t => tagsBuilder += (t.key -> t.value)) colferContext.tags.longs.foreach(t => tagsBuilder += (t.key -> t.value)) colferContext.tags.booleans.foreach(t => tagsBuilder += (t.key -> t.value)) @@ -209,11 +208,11 @@ object BinaryPropagation { val output = _streamPool.get() val contextOutgoingBuffer = _contextBufferPool.get() - if(context.tags.nonEmpty() || settings.includeUpstreamName) { + if (context.tags.nonEmpty() || settings.includeUpstreamName) { val tagsData = new ColferTags() val strings = Array.newBuilder[ColferStringTag] - if(context.tags.nonEmpty()) { + if (context.tags.nonEmpty()) { val longs = Array.newBuilder[ColferLongTag] val booleans = Array.newBuilder[ColferBooleanTag] @@ -241,7 +240,7 @@ object BinaryPropagation { tagsData.setBooleans(booleans.result()) } - if(settings.includeUpstreamName) { + if (settings.includeUpstreamName) { val st = new ColferStringTag() st.setKey(TagKeys.UpstreamName) st.setValue(Kamon.environment.service) @@ -252,7 +251,6 @@ object BinaryPropagation { contextData.setTags(tagsData) } - val entriesBuilder = Array.newBuilder[ColferEntry] context.entries().foreach { entry => settings.outgoingEntries.get(entry.key).foreach { entryWriter => @@ -300,16 +298,21 @@ object BinaryPropagation { private val log = LoggerFactory.getLogger(classOf[BinaryPropagation.Settings]) def from(config: Config): BinaryPropagation.Settings = { - def buildInstances[ExpectedType : ClassTag](mappings: Map[String, String]): Map[String, ExpectedType] = { + def buildInstances[ExpectedType: ClassTag](mappings: Map[String, String]): Map[String, ExpectedType] = { val instanceMap = Map.newBuilder[String, ExpectedType] mappings.foreach { case (contextKey, componentClass) => try { instanceMap += (contextKey -> ClassLoading.createInstance[ExpectedType](componentClass, Nil)) - } catch { case exception: Exception => log.warn("Failed to instantiate {} [{}] due to []", - implicitly[ClassTag[ExpectedType]].runtimeClass.getName, componentClass, exception) - } + } catch { + case exception: Exception => log.warn( + "Failed to instantiate {} [{}] due to []", + implicitly[ClassTag[ExpectedType]].runtimeClass.getName, + componentClass, + exception + ) + } } instanceMap.result() diff --git a/core/kamon-core/src/main/scala/kamon/context/Context.scala b/core/kamon-core/src/main/scala/kamon/context/Context.scala index d1a473222..14d631831 100644 --- a/core/kamon-core/src/main/scala/kamon/context/Context.scala +++ b/core/kamon-core/src/main/scala/kamon/context/Context.scala @@ -22,7 +22,6 @@ import kamon.tag.TagSet import kamon.trace.Span import kamon.util.UnifiedMap - /** * An immutable set of information that is tied to the processing of single operation in a service. A Context instance * can contain tags and entries. @@ -44,10 +43,10 @@ class Context private (private val _underlying: UnifiedMap[String, Any], private * from the provided key will be returned. */ def get[T](key: Context.Key[T]): T = { - if(key == Span.Key) + if (key == Span.Key) _span.asInstanceOf[T] else - _underlying.getOrDefault(key.name, key.emptyValue).asInstanceOf[T] + _underlying.getOrDefault(key.name, key.emptyValue).asInstanceOf[T] } /** @@ -62,7 +61,7 @@ class Context private (private val _underlying: UnifiedMap[String, Any], private * associated with another value then the previous value will be discarded and overwritten with the provided one. */ def withEntry[T](key: Context.Key[T], value: T): Context = { - if(key == Span.Key) + if (key == Span.Key) new Context(_underlying, value.asInstanceOf[Span], tags) else { val mergedEntries = new UnifiedMap[String, Any](_underlying.size() + 1) @@ -77,9 +76,9 @@ class Context private (private val _underlying: UnifiedMap[String, Any], private * Creates a new Context without the specified Context entry. */ def withoutEntry[T](key: Context.Key[T]): Context = { - if(_underlying.containsKey(key.name)) { + if (_underlying.containsKey(key.name)) { if (key == Span.Key) - if(_span.isEmpty) this else new Context(_underlying, Span.Empty, tags) + if (_span.isEmpty) this else new Context(_underlying, Span.Empty, tags) else { val mergedEntries = new UnifiedMap[String, Any](_underlying.size()) mergedEntries.putAll(_underlying) @@ -143,7 +142,7 @@ class Context private (private val _underlying: UnifiedMap[String, Any], private !_processedSpanEntry || _entriesIterator.hasNext override def next(): Context.Entry = { - if(!_processedSpanEntry) { + if (!_processedSpanEntry) { _processedSpanEntry = true _entry.key = Span.Key.name _entry.value = _span @@ -163,7 +162,7 @@ class Context private (private val _underlying: UnifiedMap[String, Any], private .append(_span.toString) val iterator = _underlying.entrySet().iterator() - while(iterator.hasNext) { + while (iterator.hasNext) { val pair = iterator.next() sb.append(",") .append(pair.getKey) @@ -192,7 +191,7 @@ object Context { */ def of(tags: TagSet): Context = new Context(_emptyEntries, Span.Empty, tags) - + /** * Creates a new Context instance with one tag. */ @@ -215,7 +214,7 @@ object Context { * Creates a new Context instance with the provided key and no tags. */ def of[T](key: Context.Key[T], value: T): Context = { - if(key == Span.Key) + if (key == Span.Key) new Context(_emptyEntries, value.asInstanceOf[Span], TagSet.Empty) else new Context(UnifiedMap.newWithKeysValues(key.name, value), Span.Empty, TagSet.Empty) @@ -225,7 +224,7 @@ object Context { * Creates a new Context instance with a single entry and the provided tags. */ def of[T](key: Context.Key[T], value: T, tags: TagSet): Context = { - if(key == Span.Key) + if (key == Span.Key) new Context(_emptyEntries, value.asInstanceOf[Span], tags) else new Context(UnifiedMap.newWithKeysValues(key.name, value), Span.Empty, tags) @@ -235,9 +234,9 @@ object Context { * Creates a new Context instance with two entries and no tags. */ def of[T, U](keyOne: Context.Key[T], valueOne: T, keyTwo: Context.Key[U], valueTwo: U): Context = { - if(keyOne == Span.Key) + if (keyOne == Span.Key) new Context(UnifiedMap.newWithKeysValues(keyTwo.name, valueTwo), valueOne.asInstanceOf[Span], TagSet.Empty) - else if(keyTwo == Span.Key) + else if (keyTwo == Span.Key) new Context(UnifiedMap.newWithKeysValues(keyOne.name, valueOne), valueTwo.asInstanceOf[Span], TagSet.Empty) else new Context(UnifiedMap.newWithKeysValues(keyOne.name, valueOne, keyTwo.name, valueTwo), Span.Empty, TagSet.Empty) @@ -247,9 +246,9 @@ object Context { * Creates a new Context instance with two entries and the provided tags. */ def of[T, U](keyOne: Context.Key[T], valueOne: T, keyTwo: Context.Key[U], valueTwo: U, tags: TagSet): Context = { - if(keyOne == Span.Key) + if (keyOne == Span.Key) new Context(UnifiedMap.newWithKeysValues(keyTwo.name, valueTwo), valueOne.asInstanceOf[Span], tags) - else if(keyTwo == Span.Key) + else if (keyTwo == Span.Key) new Context(UnifiedMap.newWithKeysValues(keyOne.name, valueOne), valueTwo.asInstanceOf[Span], tags) else new Context(UnifiedMap.newWithKeysValues(keyOne.name, valueOne, keyTwo.name, valueTwo), Span.Empty, tags) @@ -291,4 +290,4 @@ object Context { private[context] case class Mutable(var key: String, var value: Any) extends Entry } -} \ No newline at end of file +} diff --git a/core/kamon-core/src/main/scala/kamon/context/HttpPropagation.scala b/core/kamon-core/src/main/scala/kamon/context/HttpPropagation.scala index 11c2c0665..01cc3e132 100644 --- a/core/kamon-core/src/main/scala/kamon/context/HttpPropagation.scala +++ b/core/kamon-core/src/main/scala/kamon/context/HttpPropagation.scala @@ -61,12 +61,13 @@ object HttpPropagation { def write(header: String, value: String): Unit } - - /** * Create a new HTTP propagation instance from the provided configuration. */ - def from(propagationConfig: Config, identifierScheme: String): Propagation[HttpPropagation.HeaderReader, HttpPropagation.HeaderWriter] = { + def from( + propagationConfig: Config, + identifierScheme: String + ): Propagation[HttpPropagation.HeaderReader, HttpPropagation.HeaderWriter] = { new HttpPropagation.Default(Settings.from(propagationConfig, identifierScheme)) } @@ -110,7 +111,7 @@ object HttpPropagation { } } - //apply filter on tags on the exclusion list + // apply filter on tags on the exclusion list val filteredTags = tags.result().filterNot(kv => tagFilter(kv._1)) // Incoming Entries @@ -151,11 +152,11 @@ object HttpPropagation { } // Write the upstream name, if needed - if(settings.includeUpstreamName) + if (settings.includeUpstreamName) appendTag(Span.TagKeys.UpstreamName, Kamon.environment.service) // Write the context tags header. - if(contextTagsHeader.nonEmpty) { + if (contextTagsHeader.nonEmpty) { writer.write(settings.tagsHeaderName, contextTagsHeader.result()) } @@ -165,7 +166,8 @@ object HttpPropagation { try { entryWriter.write(context, writer) } catch { - case NonFatal(t) => log.warn("Failed to write entry [{}] due to: {}", entryName.asInstanceOf[Any], t.asInstanceOf[Any]) + case NonFatal(t) => + log.warn("Failed to write entry [{}] due to: {}", entryName.asInstanceOf[Any], t.asInstanceOf[Any]) } } } @@ -176,8 +178,8 @@ object HttpPropagation { /** * Filter for checking the tag towards the configured filter from ''kamon.propagation.http.default.tags.filter'' */ - private def tagFilter(tag:Tag):Boolean = tagFilter(tag.key) - private def tagFilter(tagName:String):Boolean = settings.tagsFilter.exists(_.accept(tagName)) + private def tagFilter(tag: Tag): Boolean = tagFilter(tag.key) + private def tagFilter(tagName: String): Boolean = settings.tagsFilter.exists(_.accept(tagName)) /** * Tries to infer and parse a value into one of the supported tag types: String, Long or Boolean by looking for the @@ -187,7 +189,7 @@ object HttpPropagation { if (value.length < 2) // Empty and short values definitely do not have type indicators. value else { - if(value.startsWith(_longTypePrefix)) { + if (value.startsWith(_longTypePrefix)) { // Try to parse the content as a Long value. val remaining = value.substring(2) try { @@ -196,12 +198,12 @@ object HttpPropagation { case _: java.lang.NumberFormatException => remaining } - } else if(value.startsWith(_booleanTypePrefix)) { + } else if (value.startsWith(_booleanTypePrefix)) { // Try to parse the content as a Boolean value. val remaining = value.substring(2) - if(remaining == "true") + if (remaining == "true") true - else if(remaining == "false") + else if (remaining == "false") false else remaining @@ -243,7 +245,7 @@ object HttpPropagation { ) def from(config: Config, identifierScheme: String): Settings = { - def buildInstances[ExpectedType : ClassTag](mappings: Map[String, String]): Map[String, ExpectedType] = { + def buildInstances[ExpectedType: ClassTag](mappings: Map[String, String]): Map[String, ExpectedType] = { val instanceMap = Map.newBuilder[String, ExpectedType] mappings.foreach { @@ -258,8 +260,12 @@ object HttpPropagation { try { instanceMap += (contextKey -> ClassLoading.createInstance[ExpectedType](componentClass, Nil)) } catch { - case exception: Exception => log.warn("Failed to instantiate {} [{}] due to []", - implicitly[ClassTag[ExpectedType]].runtimeClass.getName, componentClass, exception) + case exception: Exception => log.warn( + "Failed to instantiate {} [{}] due to []", + implicitly[ClassTag[ExpectedType]].runtimeClass.getName, + componentClass, + exception + ) } })(readerWriter => instanceMap += (contextKey -> readerWriter.asInstanceOf[ExpectedType])) } @@ -271,8 +277,10 @@ object HttpPropagation { val tagsIncludeUpstreamName = config.getBoolean("tags.include-upstream-name") val tagsFilter = config.getStringList("tags.filter").asScala.map(Glob).toSeq val tagsMappings = config.getConfig("tags.mappings").pairs - val incomingEntries = buildInstances[Propagation.EntryReader[HeaderReader]](config.getConfig("entries.incoming").pairs) - val outgoingEntries = buildInstances[Propagation.EntryWriter[HeaderWriter]](config.getConfig("entries.outgoing").pairs) + val incomingEntries = + buildInstances[Propagation.EntryReader[HeaderReader]](config.getConfig("entries.incoming").pairs) + val outgoingEntries = + buildInstances[Propagation.EntryWriter[HeaderWriter]](config.getConfig("entries.outgoing").pairs) Settings(tagsHeaderName, tagsIncludeUpstreamName, tagsFilter, tagsMappings, incomingEntries, outgoingEntries) } diff --git a/core/kamon-core/src/main/scala/kamon/context/Storage.scala b/core/kamon-core/src/main/scala/kamon/context/Storage.scala index da82a07a9..6113aea59 100644 --- a/core/kamon-core/src/main/scala/kamon/context/Storage.scala +++ b/core/kamon-core/src/main/scala/kamon/context/Storage.scala @@ -68,7 +68,6 @@ object Storage { } } - /** * A ThreadLocal context storage that allows the scope to be closed in a different * thread than the thread where store(..) was called. @@ -138,7 +137,6 @@ object Storage { new Storage.ThreadLocal() } - /** * A Storage implementation that keeps track of all Contexts across all Threads in the application and exposes them * through its companion object. Using the Debug storage can only be enabled when the System Property @@ -199,7 +197,7 @@ object Storage { * Contains information about the current context in a thread. The lastUpdateStackTracer can be either a store or * a scope close, depending on what was the last action executed on the thread. */ - case class ThreadContext ( + case class ThreadContext( thread: Thread, currentContext: Context, lastUpdateStackTrace: String @@ -214,7 +212,7 @@ object Storage { val contexts = Seq.newBuilder[ThreadContext] val threads = _allThreadContexts.iterator() - while(threads.hasNext) { + while (threads.hasNext) { val threadEntry = threads.next() contexts += ThreadContext( thread = threadEntry.get(1).asInstanceOf[Thread], @@ -230,7 +228,9 @@ object Storage { allThreadContexts() .filter(_.currentContext.nonEmpty()) .foreach { tc => - println(s"Thread [${tc.thread.getName}] has Context [${tc.currentContext}]. Last updated at: \n ${tc.lastUpdateStackTrace}") + println( + s"Thread [${tc.thread.getName}] has Context [${tc.currentContext}]. Last updated at: \n ${tc.lastUpdateStackTrace}" + ) } } } diff --git a/core/kamon-core/src/main/scala/kamon/metric/Counter.scala b/core/kamon-core/src/main/scala/kamon/metric/Counter.scala index 3ed0190d4..1cb7d1887 100644 --- a/core/kamon-core/src/main/scala/kamon/metric/Counter.scala +++ b/core/kamon-core/src/main/scala/kamon/metric/Counter.scala @@ -22,7 +22,6 @@ import kamon.metric.Metric.{BaseMetric, BaseMetricAutoUpdate} import kamon.tag.TagSet import org.slf4j.LoggerFactory - /** * Instrument that tracks a monotonically increasing value. */ @@ -39,7 +38,6 @@ trait Counter extends Instrument[Counter, Metric.Settings.ForValueInstrument] { def increment(times: Long): Counter } - object Counter { private val _logger = LoggerFactory.getLogger(classOf[Counter]) @@ -65,22 +63,23 @@ object Counter { val diff = currentValue - _previousValue _previousValue = currentValue - if(diff >= 0) + if (diff >= 0) counter.increment(diff) else - _logger.warn(s"Ignoring negative delta [$diff] when trying to update counter [${counter.metric.name},${counter.tags}]") + _logger.warn( + s"Ignoring negative delta [$diff] when trying to update counter [${counter.metric.name},${counter.tags}]" + ) } } - /** * LongAdder-based counter implementation. LongAdder counters are safe to share across threads and provide superior * write performance over Atomic values in cases where the writes largely outweigh the reads, which is the common * case in Kamon counters (writing every time something needs to be tracked, reading roughly once per minute). */ - class LongAdder(val metric: BaseMetric[Counter, Metric.Settings.ForValueInstrument,Long], val tags: TagSet) + class LongAdder(val metric: BaseMetric[Counter, Metric.Settings.ForValueInstrument, Long], val tags: TagSet) extends Counter with Instrument.Snapshotting[Long] - with BaseMetricAutoUpdate[Counter, Metric.Settings.ForValueInstrument,Long] { + with BaseMetricAutoUpdate[Counter, Metric.Settings.ForValueInstrument, Long] { private val _adder = new kamon.jsr166.LongAdder() @@ -90,7 +89,7 @@ object Counter { } override def increment(times: Long): Counter = { - if(times >= 0) + if (times >= 0) _adder.add(times) else _logger.warn(s"Ignoring an attempt to decrease a counter by [$times] on [${metric.name},${tags}]") @@ -99,12 +98,12 @@ object Counter { } override def snapshot(resetState: Boolean): Long = - if(resetState) - _adder.sumAndReset() + if (resetState) + _adder.sumAndReset() else - _adder.sum() + _adder.sum() - override def baseMetric: BaseMetric[Counter, Metric.Settings.ForValueInstrument,Long] = + override def baseMetric: BaseMetric[Counter, Metric.Settings.ForValueInstrument, Long] = metric } } diff --git a/core/kamon-core/src/main/scala/kamon/metric/Distribution.scala b/core/kamon-core/src/main/scala/kamon/metric/Distribution.scala index a6834923e..9b592ac41 100644 --- a/core/kamon-core/src/main/scala/kamon/metric/Distribution.scala +++ b/core/kamon-core/src/main/scala/kamon/metric/Distribution.scala @@ -22,7 +22,6 @@ import kamon.metric.Histogram.DistributionSnapshotBuilder import org.HdrHistogram.{BaseLocalHdrHistogram, ZigZag} import org.slf4j.LoggerFactory - /** * A distribution of values observed by an instrument. All Kamon distributions are based on the HdrHistogram and as * such, they represent a distribution of values within a configured range and precision. By default, all instruments @@ -100,6 +99,7 @@ object Distribution { * Describes a single bucket within a distribution. */ trait Bucket { + /** * Value at which the bucket starts */ @@ -142,7 +142,6 @@ object Distribution { def merge(left: Distribution, right: Distribution): Distribution = merge(left, right, left.dynamicRange) - /** * Merges two distributions into a new one, which includes the values from both distributions, adjusting the values * to the provided dynamic range if necessary. @@ -182,12 +181,18 @@ object Distribution { * If the distribution and target unit dimensions are not the same then a warning will be logged and the distribution * will be returned unchanged. */ - def convert(distribution: Distribution, unit: MeasurementUnit, toUnit: MeasurementUnit, toDynamicRange: DynamicRange): Distribution = { - - if(unit == toUnit && distribution.dynamicRange == toDynamicRange) + def convert( + distribution: Distribution, + unit: MeasurementUnit, + toUnit: MeasurementUnit, + toDynamicRange: DynamicRange + ): Distribution = { + + if (unit == toUnit && distribution.dynamicRange == toDynamicRange) distribution else { - val actualToUnit = if(unit.dimension == toUnit.dimension) toUnit else { + val actualToUnit = if (unit.dimension == toUnit.dimension) toUnit + else { _logger.warn( s"Can't convert distributions from the [${unit.dimension.name}] dimension into the " + s"[${toUnit.dimension.name}] dimension." @@ -196,13 +201,13 @@ object Distribution { unit } - if(unit == actualToUnit && distribution.dynamicRange == toDynamicRange) + if (unit == actualToUnit && distribution.dynamicRange == toDynamicRange) distribution else { val scaledHistogram = Histogram.Local.get(toDynamicRange) distribution.bucketsIterator.foreach(bucket => { val roundValue = Math.round(MeasurementUnit.convert(bucket.value, unit, toUnit)) - val convertedValue = if(roundValue == 0L) 1L else roundValue + val convertedValue = if (roundValue == 0L) 1L else roundValue scaledHistogram.recordValueWithCount(convertedValue, bucket.frequency) }) @@ -217,17 +222,25 @@ object Distribution { * zero run-length encoded version of the counts array in a histogram and the actual buckets and percentiles expected * to be seen by users. */ - private[kamon] class ZigZagCounts(val count: Long, minIndex: Int, maxIndex: Int, zigZagCounts: ByteBuffer, unitMagnitude: Int, - subBucketHalfCount: Int, subBucketHalfCountMagnitude: Int, val dynamicRange: DynamicRange) extends Distribution { - - val min: Long = if(count == 0) 0 else bucketValueAtIndex(minIndex) + private[kamon] class ZigZagCounts( + val count: Long, + minIndex: Int, + maxIndex: Int, + zigZagCounts: ByteBuffer, + unitMagnitude: Int, + subBucketHalfCount: Int, + subBucketHalfCountMagnitude: Int, + val dynamicRange: DynamicRange + ) extends Distribution { + + val min: Long = if (count == 0) 0 else bucketValueAtIndex(minIndex) val max: Long = bucketValueAtIndex(maxIndex) lazy val sum: Long = bucketsIterator.foldLeft(0L)((a, b) => a + (b.value * b.frequency)) def buckets: Seq[Bucket] = { val builder = Seq.newBuilder[Bucket] val allBuckets = bucketsIterator - while(allBuckets.hasNext) { + while (allBuckets.hasNext) { val b = allBuckets.next() builder += immutable.Bucket(b.value, b.frequency) } @@ -245,7 +258,7 @@ object Distribution { def next(): Bucket = { val readLong = ZigZag.getLong(buffer) - val frequency = if(readLong > 0) { + val frequency = if (readLong > 0) { readLong } else { countsArrayIndex += (-readLong.toInt) @@ -259,9 +272,9 @@ object Distribution { } } - def percentilesIterator: Iterator[Percentile] = new Iterator[Percentile]{ + def percentilesIterator: Iterator[Percentile] = new Iterator[Percentile] { val buckets = bucketsIterator - val percentile = mutable.Percentile(0D, 0, 0) + val percentile = mutable.Percentile(0d, 0, 0) var countUnderQuantile = 0L def hasNext: Boolean = @@ -270,7 +283,7 @@ object Distribution { def next(): Percentile = { val bucket = buckets.next() countUnderQuantile += bucket.frequency - percentile.rank = (countUnderQuantile * 100D) / ZigZagCounts.this.count + percentile.rank = (countUnderQuantile * 100d) / ZigZagCounts.this.count percentile.countAtRank = countUnderQuantile percentile.value = bucket.value percentile @@ -279,9 +292,9 @@ object Distribution { def percentile(p: Double): Percentile = { val percentiles = percentilesIterator - if(percentiles.hasNext) { + if (percentiles.hasNext) { var currentPercentile = percentiles.next() - while(percentiles.hasNext && currentPercentile.rank < p) { + while (percentiles.hasNext && currentPercentile.rank < p) { currentPercentile = percentiles.next() } @@ -290,11 +303,10 @@ object Distribution { } else immutable.Percentile(p, 0, 0) } - def percentiles: Seq[Percentile] = { val builder = Seq.newBuilder[Percentile] val allPercentiles = percentilesIterator - while(allPercentiles.hasNext) { + while (allPercentiles.hasNext) { val p = allPercentiles.next() builder += immutable.Percentile(p.rank, p.value, p.countAtRank) } diff --git a/core/kamon-core/src/main/scala/kamon/metric/Gauge.scala b/core/kamon-core/src/main/scala/kamon/metric/Gauge.scala index 1533aa148..6622d835f 100644 --- a/core/kamon-core/src/main/scala/kamon/metric/Gauge.scala +++ b/core/kamon-core/src/main/scala/kamon/metric/Gauge.scala @@ -21,7 +21,7 @@ import java.util.function.LongUnaryOperator import kamon.metric.Metric.{BaseMetric, BaseMetricAutoUpdate} import kamon.tag.TagSet -import java.lang.Double.{longBitsToDouble,doubleToLongBits} +import java.lang.Double.{longBitsToDouble, doubleToLongBits} /** * Instrument that tracks the latest observed value of a given measure. @@ -47,7 +47,7 @@ trait Gauge extends Instrument[Gauge, Metric.Settings.ForValueInstrument] { * Decrements the current value the provided number of times. */ def decrement(times: Double): Gauge - + /** * Sets the current value of the gauge to the provided value. */ @@ -60,10 +60,12 @@ object Gauge { /** * Gauge implementation backed by a volatile variable. */ - class Volatile(val metric: BaseMetric[Gauge, Metric.Settings.ForValueInstrument, Double], val tags: TagSet) extends Gauge - with Instrument.Snapshotting[Double] with BaseMetricAutoUpdate[Gauge, Metric.Settings.ForValueInstrument, Double] { + class Volatile(val metric: BaseMetric[Gauge, Metric.Settings.ForValueInstrument, Double], val tags: TagSet) + extends Gauge + with Instrument.Snapshotting[Double] + with BaseMetricAutoUpdate[Gauge, Metric.Settings.ForValueInstrument, Double] { - //https://stackoverflow.com/questions/5505460/java-is-there-no-atomicfloat-or-atomicdouble + // https://stackoverflow.com/questions/5505460/java-is-there-no-atomicfloat-or-atomicdouble private val _currentValue = new AtomicLong(0) override def increment(): Gauge = increment(1) @@ -72,7 +74,7 @@ object Gauge { _currentValue.updateAndGet(new LongUnaryOperator { override def applyAsLong(v: Long): Long = { val newValue: Double = longBitsToDouble(v) + times - if(newValue < 0) v else doubleToLongBits(newValue) + if (newValue < 0) v else doubleToLongBits(newValue) } }) this @@ -84,14 +86,14 @@ object Gauge { _currentValue.updateAndGet(new LongUnaryOperator { override def applyAsLong(v: Long): Long = { val newValue: Double = longBitsToDouble(v) - times - if(newValue < 0) v else doubleToLongBits(newValue) + if (newValue < 0) v else doubleToLongBits(newValue) } }) this } override def update(newValue: Double): Gauge = { - if(newValue >= 0D) + if (newValue >= 0d) _currentValue.set(doubleToLongBits(newValue)) this @@ -104,6 +106,3 @@ object Gauge { metric } } - - - diff --git a/core/kamon-core/src/main/scala/kamon/metric/Histogram.scala b/core/kamon-core/src/main/scala/kamon/metric/Histogram.scala index b82db650a..93cb7cd10 100644 --- a/core/kamon-core/src/main/scala/kamon/metric/Histogram.scala +++ b/core/kamon-core/src/main/scala/kamon/metric/Histogram.scala @@ -23,7 +23,6 @@ import kamon.tag.TagSet import org.HdrHistogram.{BaseAtomicHdrHistogram, BaseLocalHdrHistogram, HdrHistogramInternalState, ZigZag} import org.slf4j.LoggerFactory - /** * Instrument that tracks the distribution of values within a configured range and precision. */ @@ -45,7 +44,6 @@ trait Histogram extends Instrument[Histogram, Metric.Settings.ForDistributionIns } - object Histogram { private val _logger = LoggerFactory.getLogger(classOf[Histogram]) @@ -54,8 +52,11 @@ object Histogram { * Histogram implementation with thread safety guarantees. Instances of this class can be safely shared across * threads and updated concurrently. */ - class Atomic(val metric: BaseMetric[Histogram, Metric.Settings.ForDistributionInstrument, Distribution], - val tags: TagSet, val dynamicRange: DynamicRange) extends BaseAtomicHdrHistogram(dynamicRange) with Histogram + class Atomic( + val metric: BaseMetric[Histogram, Metric.Settings.ForDistributionInstrument, Distribution], + val tags: TagSet, + val dynamicRange: DynamicRange + ) extends BaseAtomicHdrHistogram(dynamicRange) with Histogram with DistributionSnapshotBuilder with BaseMetricAutoUpdate[Histogram, Metric.Settings.ForDistributionInstrument, Distribution] { @@ -67,10 +68,11 @@ object Histogram { val highestTrackableValue = getHighestTrackableValue() recordValue(highestTrackableValue) - _logger.warn ( + _logger.warn( s"Failed to record value [$value] on [${metric.name},${tags}] because the value is outside of the " + s"configured range. The recorded value was adjusted to the highest trackable value [$highestTrackableValue]. " + - "You might need to change your dynamic range configuration for this metric", e + "You might need to change your dynamic range configuration for this metric", + e ) } @@ -85,10 +87,11 @@ object Histogram { val highestTrackableValue = getHighestTrackableValue() recordValueWithCount(highestTrackableValue, times) - _logger.warn ( + _logger.warn( s"Failed to record value [$value] on [${metric.name},${tags}] because the value is outside of the " + s"configured range. The recorded value was adjusted to the highest trackable value [$highestTrackableValue]. " + - "You might need to change your dynamic range configuration for this metric", e + "You might need to change your dynamic range configuration for this metric", + e ) } @@ -117,25 +120,24 @@ object Histogram { var maxIndex = 0 var totalCount = 0L - while(index < countsLimit) { - val countAtIndex = if(resetState) getAndSetFromCountsArray(index, 0L) else getFromCountsArray(index) + while (index < countsLimit) { + val countAtIndex = if (resetState) getAndSetFromCountsArray(index, 0L) else getFromCountsArray(index) var zerosCount = 0L - if(countAtIndex == 0L) { + if (countAtIndex == 0L) { index += 1 zerosCount = 1 - while(index < countsLimit && getFromCountsArray(index) == 0L) { + while (index < countsLimit && getFromCountsArray(index) == 0L) { index += 1 zerosCount += 1 } } - if(zerosCount > 0) { - if(index < countsLimit) + if (zerosCount > 0) { + if (index < countsLimit) ZigZag.putLong(buffer, -zerosCount) - } - else { - if(minIndex > index) + } else { + if (minIndex > index) minIndex = index maxIndex = index @@ -150,8 +152,16 @@ object Histogram { buffer.get(zigZagCounts) val zigZagCountsBuffer = ByteBuffer.wrap(zigZagCounts).asReadOnlyBuffer() - val distribution = new Distribution.ZigZagCounts(totalCount, minIndex, maxIndex, zigZagCountsBuffer, - getUnitMagnitude(), getSubBucketHalfCount(), getSubBucketHalfCountMagnitude(), dynamicRange) + val distribution = new Distribution.ZigZagCounts( + totalCount, + minIndex, + maxIndex, + zigZagCountsBuffer, + getUnitMagnitude(), + getSubBucketHalfCount(), + getSubBucketHalfCountMagnitude(), + dynamicRange + ) distribution } @@ -170,7 +180,7 @@ object Histogram { * range. */ private[kamon] class Local(val dynamicRange: DynamicRange) extends BaseLocalHdrHistogram(dynamicRange) - with Instrument.Snapshotting[Distribution] with DistributionSnapshotBuilder + with Instrument.Snapshotting[Distribution] with DistributionSnapshotBuilder private[kamon] object Local { diff --git a/core/kamon-core/src/main/scala/kamon/metric/Instrument.scala b/core/kamon-core/src/main/scala/kamon/metric/Instrument.scala index 9689adbde..f82890dc5 100644 --- a/core/kamon-core/src/main/scala/kamon/metric/Instrument.scala +++ b/core/kamon-core/src/main/scala/kamon/metric/Instrument.scala @@ -54,7 +54,6 @@ trait Instrument[Inst <: Instrument[Inst, Sett], Sett <: Metric.Settings] extend override def withTags(tags: TagSet): Inst = metric.withTags(this.tags.withTags(tags)) - /** * Schedules a call to the provided consumer with a reference to this histogram as parameter, overriding the metric's * auto-update interval. @@ -90,7 +89,7 @@ object Instrument { * Snapshot of an instrument's state at a given point. Snapshots are expected to have either Long, Double or * Distribution values, depending on the instrument type. */ - case class Snapshot[T] ( + case class Snapshot[T]( tags: TagSet, value: T ) @@ -121,4 +120,3 @@ object Instrument { val RangeSampler = Type("rangeSampler", classOf[Metric.RangeSampler]) } } - diff --git a/core/kamon-core/src/main/scala/kamon/metric/InstrumentGroup.scala b/core/kamon-core/src/main/scala/kamon/metric/InstrumentGroup.scala index 6c87bb96d..284a5484f 100644 --- a/core/kamon-core/src/main/scala/kamon/metric/InstrumentGroup.scala +++ b/core/kamon-core/src/main/scala/kamon/metric/InstrumentGroup.scala @@ -41,32 +41,48 @@ abstract class InstrumentGroup(val commonTags: TagSet) { * Registers and returns an instrument of the provided metric with the common tags and the additionally provided * key/value pair. */ - def register[Inst <: Instrument[Inst, Sett], Sett <: Metric.Settings](metric: Metric[Inst, Sett], key: String, value: String): Inst = + def register[Inst <: Instrument[Inst, Sett], Sett <: Metric.Settings]( + metric: Metric[Inst, Sett], + key: String, + value: String + ): Inst = registerInstrument(metric, commonTags.withTag(key, value)) /** * Registers and returns an instrument of the provided metric with the common tags and the additionally provided * key/value pair. */ - def register[Inst <: Instrument[Inst, Sett], Sett <: Metric.Settings](metric: Metric[Inst, Sett], key: String, value: Long): Inst = + def register[Inst <: Instrument[Inst, Sett], Sett <: Metric.Settings]( + metric: Metric[Inst, Sett], + key: String, + value: Long + ): Inst = registerInstrument(metric, commonTags.withTag(key, value)) /** * Registers and returns an instrument of the provided metric with the common tags and the additionally provided * key/value pair. */ - def register[Inst <: Instrument[Inst, Sett], Sett <: Metric.Settings](metric: Metric[Inst, Sett], key: String, value: Boolean): Inst = + def register[Inst <: Instrument[Inst, Sett], Sett <: Metric.Settings]( + metric: Metric[Inst, Sett], + key: String, + value: Boolean + ): Inst = registerInstrument(metric, commonTags.withTag(key, value)) /** * Registers and returns an instrument of the provided metric with the common tags and the additionally provided tags. */ - def register[Inst <: Instrument[Inst, Sett], Sett <: Metric.Settings](metric: Metric[Inst, Sett], extraTags: TagSet): Inst = + def register[Inst <: Instrument[Inst, Sett], Sett <: Metric.Settings]( + metric: Metric[Inst, Sett], + extraTags: TagSet + ): Inst = registerInstrument(metric, commonTags.withTags(extraTags)) - - private def registerInstrument[Inst <: Instrument[Inst, Sett], Sett <: Metric.Settings](metric: Metric[Inst, Sett], - tags: TagSet): Inst = synchronized { + private def registerInstrument[Inst <: Instrument[Inst, Sett], Sett <: Metric.Settings]( + metric: Metric[Inst, Sett], + tags: TagSet + ): Inst = synchronized { val instrument = metric.withTags(tags) _groupInstruments = instrument :: _groupInstruments instrument @@ -76,6 +92,6 @@ abstract class InstrumentGroup(val commonTags: TagSet) { * Removes all instruments that were registered by this group. */ def remove(): Unit = synchronized { - _groupInstruments foreach(_.remove()) + _groupInstruments foreach (_.remove()) } -} \ No newline at end of file +} diff --git a/core/kamon-core/src/main/scala/kamon/metric/MeasurementUnit.scala b/core/kamon-core/src/main/scala/kamon/metric/MeasurementUnit.scala index 501d61a7c..309d0c3a7 100644 --- a/core/kamon-core/src/main/scala/kamon/metric/MeasurementUnit.scala +++ b/core/kamon-core/src/main/scala/kamon/metric/MeasurementUnit.scala @@ -25,7 +25,7 @@ import org.slf4j.LoggerFactory * an instrument has a specified MeasurementUnit the reporters can apply scaling in case it's necessary to meet the * backend's requirements. */ -case class MeasurementUnit ( +case class MeasurementUnit( dimension: MeasurementUnit.Dimension, magnitude: MeasurementUnit.Magnitude ) @@ -38,20 +38,20 @@ object MeasurementUnit { * Default measurement unit used when there is no knowledge of the actual unit being measured or none of the * available units matches the actual unit. */ - val none = MeasurementUnit(Dimension.None, Magnitude("none", 1D)) + val none = MeasurementUnit(Dimension.None, Magnitude("none", 1d)) /** * Unit for values that represent the ratio between two indicators, as a fraction of 100. Metrics using this unit * will usually have a range between 0 and 100, although there are no hard limitations on that. */ - val percentage = MeasurementUnit(Dimension.Percentage, Magnitude("percentage", 1D)) + val percentage = MeasurementUnit(Dimension.Percentage, Magnitude("percentage", 1d)) /** * Group of units for measurements in the time dimension. All metrics tracking latency will use one of these units, * typically the nanoseconds unit. */ val time: TimeUnits = new TimeUnits { - val seconds = timeUnit("seconds", 1D) + val seconds = timeUnit("seconds", 1d) val milliseconds = timeUnit("milliseconds", 1e-3) val microseconds = timeUnit("microseconds", 1e-6) val nanoseconds = timeUnit("nanoseconds", 1e-9) @@ -73,10 +73,12 @@ object MeasurementUnit { * not share the same dimension a warning will be logged and the value will be returned unchanged. */ def convert(value: Double, from: MeasurementUnit, to: MeasurementUnit): Double = { - if(from.dimension != to.dimension) { - _logger.warn(s"Can't convert values from the [${from.dimension.name}] dimension into the [${to.dimension.name}] dimension.") + if (from.dimension != to.dimension) { + _logger.warn( + s"Can't convert values from the [${from.dimension.name}] dimension into the [${to.dimension.name}] dimension." + ) value - } else if(from == to) + } else if (from == to) value else (from.magnitude.scaleFactor / to.magnitude.scaleFactor) * value } diff --git a/core/kamon-core/src/main/scala/kamon/metric/Metric.scala b/core/kamon-core/src/main/scala/kamon/metric/Metric.scala index bd9ee8766..8bc512032 100644 --- a/core/kamon-core/src/main/scala/kamon/metric/Metric.scala +++ b/core/kamon-core/src/main/scala/kamon/metric/Metric.scala @@ -28,7 +28,6 @@ import scala.collection.JavaConverters.asScalaBufferConverter import scala.collection.concurrent.TrieMap import scala.collection.mutable - /** * Describes a property of a system to be measured, and contains all the necessary information to create the actual * instrument instances used to measure and record said property. Practically, a Metric can be seen as a group @@ -48,25 +47,21 @@ trait Metric[Inst <: Instrument[Inst, Sett], Sett <: Metric.Settings] extends Ta */ def name: String - /** * Short, concise and human readable explanation of what is being measured by a metric. */ def description: String - /** * Configuration settings that apply to all instruments of this metric. */ def settings: Sett - /** * Returns an instrument without tags for this metric. */ def withoutTags(): Inst - /** * Removes an instrument with the provided tags from a metric, if it exists. Returns true if the instrument existed * and was removed or false if no instrument was found with the provided tags. @@ -74,8 +69,6 @@ trait Metric[Inst <: Instrument[Inst, Sett], Sett <: Metric.Settings] extends Ta def remove(tags: TagSet): Boolean } - - object Metric { /** @@ -108,7 +101,6 @@ object Metric { */ trait RangeSampler extends Metric[kamon.metric.RangeSampler, Settings.ForDistributionInstrument] - /** * Describes the minimum settings that should be provided to all metrics. */ @@ -119,7 +111,6 @@ object Metric { */ def unit: MeasurementUnit - /** * Interval at which auto-update actions will be scheduled. */ @@ -131,24 +122,22 @@ object Metric { /** * Settings that apply to all metrics backed by instruments that produce a single value (e.g. counters and gauges). */ - case class ForValueInstrument ( + case class ForValueInstrument( unit: MeasurementUnit, autoUpdateInterval: Duration ) extends Metric.Settings - /** * Settings that apply to all metrics backed by instruments that produce value distributions (e.g. timers, range * samplers and, of course, histograms). */ - case class ForDistributionInstrument ( + case class ForDistributionInstrument( unit: MeasurementUnit, autoUpdateInterval: Duration, dynamicRange: kamon.metric.DynamicRange ) extends Metric.Settings } - /** * Exposes the required API to create metric snapshots. This API is not meant to be exposed to users. */ @@ -161,7 +150,6 @@ object Metric { def snapshot(resetState: Boolean): MetricSnapshot[Sett, Snap] } - /** * Provides basic creation, lifecycle, tagging, scheduling and snapshotting operations for Kamon metrics. This base * metric keeps track of all instruments created for a given metric and ensures that every time an instrument is @@ -178,14 +166,13 @@ object Metric { type InstrumentBuilder[Inst <: Instrument[Inst, Sett], Sett <: Metric.Settings, Snap] = (BaseMetric[Inst, Sett, Snap], TagSet) => RichInstrument[Inst, Sett, Snap] - - abstract class BaseMetric[Inst <: Instrument[Inst, Sett], Sett <: Metric.Settings, Snap] ( - val name: String, - val description: String, - val settings: Sett, - instrumentBuilder: InstrumentBuilder[Inst, Sett, Snap], - scheduler: Option[ScheduledExecutorService]) - extends Metric[Inst, Sett] with Metric.Snapshotting[Sett, Snap] { + abstract class BaseMetric[Inst <: Instrument[Inst, Sett], Sett <: Metric.Settings, Snap]( + val name: String, + val description: String, + val settings: Sett, + instrumentBuilder: InstrumentBuilder[Inst, Sett, Snap], + scheduler: Option[ScheduledExecutorService] + ) extends Metric[Inst, Sett] with Metric.Snapshotting[Sett, Snap] { @volatile private var _scheduler: Option[ScheduledExecutorService] = scheduler private val _instruments = TrieMap.empty[TagSet, InstrumentEntry] @@ -220,7 +207,7 @@ object Metric { _instruments.foreach { case (tags, entry) => val instrumentSnapshot = entry.instrument.snapshot(resetState) - if(entry.removeOnNextSnapshot && resetState) + if (entry.removeOnNextSnapshot && resetState) _instruments.remove(tags) instrumentSnapshots = Instrument.Snapshot(tags, instrumentSnapshot) :: instrumentSnapshots @@ -235,7 +222,12 @@ object Metric { case (_, entry) => entry.actions.foreach(action => { val (runnable, interval) = action - entry.scheduledActions += scheduler.scheduleAtFixedRate(runnable, interval.toNanos, interval.toNanos, TimeUnit.NANOSECONDS) + entry.scheduledActions += scheduler.scheduleAtFixedRate( + runnable, + interval.toNanos, + interval.toNanos, + TimeUnit.NANOSECONDS + ) }) } } @@ -257,7 +249,8 @@ object Metric { _instruments.get(instrument.tags).map { entry => _scheduler match { case Some(scheduler) => - val scheduledAction = scheduler.scheduleAtFixedRate(action, interval.toNanos, interval.toNanos, TimeUnit.NANOSECONDS) + val scheduledAction = + scheduler.scheduleAtFixedRate(action, interval.toNanos, interval.toNanos, TimeUnit.NANOSECONDS) entry.scheduledActions += (scheduledAction) entry.actions += ((action, interval)) @@ -268,7 +261,7 @@ object Metric { } def status(): Status.Metric = - Status.Metric ( + Status.Metric( name, description, settings.unit, @@ -279,10 +272,14 @@ object Metric { /** Used by the Status API only */ protected def instrumentType: Instrument.Type - protected def buildMetricSnapshot(metric: Metric[Inst, Sett], instruments: Seq[Instrument.Snapshot[Snap]]): MetricSnapshot[Sett, Snap] + protected def buildMetricSnapshot( + metric: Metric[Inst, Sett], + instruments: Seq[Instrument.Snapshot[Snap]] + ): MetricSnapshot[Sett, Snap] private def lookupInstrument(tags: TagSet): Inst = { - val entry = _instruments.atomicGetOrElseUpdate(tags, newInstrumentEntry(tags), cleanupStaleEntry, triggerDefaultSchedule) + val entry = + _instruments.atomicGetOrElseUpdate(tags, newInstrumentEntry(tags), cleanupStaleEntry, triggerDefaultSchedule) entry.removeOnNextSnapshot = false entry.instrument } @@ -301,7 +298,7 @@ object Metric { private def cleanupStaleEntry(entry: InstrumentEntry): Unit = entry.scheduledActions.foreach(sa => sa.cancel(false)) - private class InstrumentEntry ( + private class InstrumentEntry( val instrument: RichInstrument[Inst, Sett, Snap], val actions: mutable.Buffer[(Runnable, Duration)], val scheduledActions: mutable.Buffer[ScheduledFuture[_]], @@ -313,7 +310,7 @@ object Metric { * Handles registration of auto-update actions on a base metric. */ trait BaseMetricAutoUpdate[Inst <: Instrument[Inst, Sett], Sett <: Metric.Settings, Snap] { - self: Inst => + self: Inst => protected def baseMetric: BaseMetric[Inst, Sett, Snap] @@ -329,4 +326,4 @@ object Metric { this } } -} \ No newline at end of file +} diff --git a/core/kamon-core/src/main/scala/kamon/metric/MetricBuilding.scala b/core/kamon-core/src/main/scala/kamon/metric/MetricBuilding.scala index 09af87e55..26872a61b 100644 --- a/core/kamon-core/src/main/scala/kamon/metric/MetricBuilding.scala +++ b/core/kamon-core/src/main/scala/kamon/metric/MetricBuilding.scala @@ -19,7 +19,6 @@ package metric import java.time.Duration - /** * Exposes APIs for creating metrics, using a MetricRegistry as the underlying source of those metrics. Not all * possible combinations of parameters to build metrics are exposed through this interface, but it is expected to cover @@ -47,7 +46,6 @@ trait MetricBuilding { def counter(name: String, description: String, settings: Metric.Settings.ForValueInstrument): Metric.Counter = registry.counter(name, Some(description), Some(settings.unit), Some(settings.autoUpdateInterval)) - /** Creates or retrieves a Gauge-backed metric */ def gauge(name: String): Metric.Gauge = registry.gauge(name, None, None, None) @@ -68,7 +66,6 @@ trait MetricBuilding { def gauge(name: String, description: String, settings: Metric.Settings.ForValueInstrument): Metric.Gauge = registry.gauge(name, Some(description), Some(settings.unit), Some(settings.autoUpdateInterval)) - /** Creates or retrieves a Histogram-backed metric */ def histogram(name: String): Metric.Histogram = registry.histogram(name, None, None, None, None) @@ -90,13 +87,27 @@ trait MetricBuilding { registry.histogram(name, None, Some(unit), Some(dynamicRange), None) /** Creates or retrieves a Histogram-backed metric with the provided unit and dynamic range */ - def histogram(name: String, description: String, unit: MeasurementUnit, dynamicRange: DynamicRange): Metric.Histogram = + def histogram( + name: String, + description: String, + unit: MeasurementUnit, + dynamicRange: DynamicRange + ): Metric.Histogram = registry.histogram(name, Some(description), Some(unit), Some(dynamicRange), None) /** Creates or retrieves a Histogram-backed metric with the provided settings */ - def histogram(name: String, description: String, settings: Metric.Settings.ForDistributionInstrument): Metric.Histogram = - registry.histogram(name, Some(description), Some(settings.unit), Some(settings.dynamicRange), Some(settings.autoUpdateInterval)) - + def histogram( + name: String, + description: String, + settings: Metric.Settings.ForDistributionInstrument + ): Metric.Histogram = + registry.histogram( + name, + Some(description), + Some(settings.unit), + Some(settings.dynamicRange), + Some(settings.autoUpdateInterval) + ) /** Creates or retrieves a Timer-backed metric */ def timer(name: String): Metric.Timer = @@ -114,7 +125,6 @@ trait MetricBuilding { def timer(name: String, description: String, dynamicRange: DynamicRange): Metric.Timer = registry.timer(name, Some(description), Some(dynamicRange), None) - /** Creates or retrieves a RangeSampler-backed metric */ def rangeSampler(name: String): Metric.RangeSampler = registry.rangeSampler(name, None, None, None, None) @@ -136,7 +146,12 @@ trait MetricBuilding { registry.rangeSampler(name, Some(description), Some(unit), None, None) /** Creates or retrieves a RangeSampler-backed metric with the provided unit and auto-update interval */ - def rangeSampler(name: String, description: String, unit: MeasurementUnit, autoUpdateInterval: Duration): Metric.RangeSampler = + def rangeSampler( + name: String, + description: String, + unit: MeasurementUnit, + autoUpdateInterval: Duration + ): Metric.RangeSampler = registry.rangeSampler(name, Some(description), Some(unit), None, Some(autoUpdateInterval)) /** Creates or retrieves a RangeSampler-backed metric with the provided unit and dynamic range */ @@ -144,12 +159,27 @@ trait MetricBuilding { registry.rangeSampler(name, None, Some(unit), Some(dynamicRange), None) /** Creates or retrieves a RangeSampler-backed metric with the provided unit and dynamic range */ - def rangeSampler(name: String, description: String, unit: MeasurementUnit, dynamicRange: DynamicRange): Metric.RangeSampler = + def rangeSampler( + name: String, + description: String, + unit: MeasurementUnit, + dynamicRange: DynamicRange + ): Metric.RangeSampler = registry.rangeSampler(name, Some(description), Some(unit), Some(dynamicRange), None) /** Creates or retrieves a RangeSampler-backed metric with the provided settings */ - def rangeSampler(name: String, description: String, settings: Metric.Settings.ForDistributionInstrument): Metric.RangeSampler = - registry.rangeSampler(name, Some(description), Some(settings.unit), Some(settings.dynamicRange), Some(settings.autoUpdateInterval)) + def rangeSampler( + name: String, + description: String, + settings: Metric.Settings.ForDistributionInstrument + ): Metric.RangeSampler = + registry.rangeSampler( + name, + Some(description), + Some(settings.unit), + Some(settings.dynamicRange), + Some(settings.autoUpdateInterval) + ) /** * Registry from which metrics are retrieved. diff --git a/core/kamon-core/src/main/scala/kamon/metric/MetricFactory.scala b/core/kamon-core/src/main/scala/kamon/metric/MetricFactory.scala index c7d7067e5..b69580ccf 100644 --- a/core/kamon-core/src/main/scala/kamon/metric/MetricFactory.scala +++ b/core/kamon-core/src/main/scala/kamon/metric/MetricFactory.scala @@ -26,7 +26,6 @@ import kamon.util.Clock import java.util.concurrent.ScheduledExecutorService - /** * Creates new metric instances taking default and custom settings into account. This class only handles the creation * and configuration of metrics and does not do any effort on checking whether a metric has already been created or @@ -34,24 +33,28 @@ import java.util.concurrent.ScheduledExecutorService * */ class MetricFactory private ( - defaultCounterSettings: Metric.Settings.ForValueInstrument, - defaultGaugeSettings: Metric.Settings.ForValueInstrument, - defaultHistogramSettings: Metric.Settings.ForDistributionInstrument, - defaultTimerSettings: Metric.Settings.ForDistributionInstrument, - defaultRangeSamplerSettings: Metric.Settings.ForDistributionInstrument, - customSettings: Map[String, MetricFactory.CustomSettings], - clock: Clock, - scheduler: Option[ScheduledExecutorService]) { - + defaultCounterSettings: Metric.Settings.ForValueInstrument, + defaultGaugeSettings: Metric.Settings.ForValueInstrument, + defaultHistogramSettings: Metric.Settings.ForDistributionInstrument, + defaultTimerSettings: Metric.Settings.ForDistributionInstrument, + defaultRangeSamplerSettings: Metric.Settings.ForDistributionInstrument, + customSettings: Map[String, MetricFactory.CustomSettings], + clock: Clock, + scheduler: Option[ScheduledExecutorService] +) { /** * Creates a new counter-based metric, backed by the Counter.LongAdder implementation. */ - def counter(name: String, description: Option[String], unit: Option[MeasurementUnit], autoUpdateInterval: Option[Duration]): - BaseMetric[Counter, Metric.Settings.ForValueInstrument, Long] with Metric.Counter = { + def counter( + name: String, + description: Option[String], + unit: Option[MeasurementUnit], + autoUpdateInterval: Option[Duration] + ): BaseMetric[Counter, Metric.Settings.ForValueInstrument, Long] with Metric.Counter = { val metricDescription = description.getOrElse("") - val metricSettings = Metric.Settings.ForValueInstrument ( + val metricSettings = Metric.Settings.ForValueInstrument( unit.getOrElse(defaultCounterSettings.unit), resolveAutoUpdateInterval(name, autoUpdateInterval, defaultCounterSettings.autoUpdateInterval) ) @@ -59,14 +62,21 @@ class MetricFactory private ( val builder = (metric: BaseMetric[Counter, Metric.Settings.ForValueInstrument, Long], tags: TagSet) => new Counter.LongAdder(metric, tags) - new BaseMetric[Counter, Metric.Settings.ForValueInstrument, Long](name, metricDescription, metricSettings, - builder, scheduler) with Metric.Counter { + new BaseMetric[Counter, Metric.Settings.ForValueInstrument, Long]( + name, + metricDescription, + metricSettings, + builder, + scheduler + ) with Metric.Counter { override protected def instrumentType: Instrument.Type = Instrument.Type.Counter - override protected def buildMetricSnapshot(metric: Metric[Counter, Settings.ForValueInstrument], - instruments: Seq[Instrument.Snapshot[Long]]): MetricSnapshot.Values[Long] = + override protected def buildMetricSnapshot( + metric: Metric[Counter, Settings.ForValueInstrument], + instruments: Seq[Instrument.Snapshot[Long]] + ): MetricSnapshot.Values[Long] = MetricSnapshot.ofValues(metric.name, metric.description, metric.settings, instruments) } } @@ -74,11 +84,15 @@ class MetricFactory private ( /** * Creates a new counter-based metric, backed by the Counter.LongAdder implementation. */ - def gauge(name: String, description: Option[String], unit: Option[MeasurementUnit], autoUpdateInterval: Option[Duration]): - BaseMetric[Gauge, Metric.Settings.ForValueInstrument, Double] with Metric.Gauge = { + def gauge( + name: String, + description: Option[String], + unit: Option[MeasurementUnit], + autoUpdateInterval: Option[Duration] + ): BaseMetric[Gauge, Metric.Settings.ForValueInstrument, Double] with Metric.Gauge = { val metricDescription = description.getOrElse("") - val metricSettings = Metric.Settings.ForValueInstrument ( + val metricSettings = Metric.Settings.ForValueInstrument( unit.getOrElse(defaultGaugeSettings.unit), resolveAutoUpdateInterval(name, autoUpdateInterval, defaultGaugeSettings.autoUpdateInterval) ) @@ -86,14 +100,21 @@ class MetricFactory private ( val builder = (metric: BaseMetric[Gauge, Metric.Settings.ForValueInstrument, Double], tags: TagSet) => new Gauge.Volatile(metric, tags) - new BaseMetric[Gauge, Metric.Settings.ForValueInstrument, Double](name, metricDescription, metricSettings, - builder, scheduler) with Metric.Gauge { + new BaseMetric[Gauge, Metric.Settings.ForValueInstrument, Double]( + name, + metricDescription, + metricSettings, + builder, + scheduler + ) with Metric.Gauge { override protected def instrumentType: Instrument.Type = Instrument.Type.Gauge - override protected def buildMetricSnapshot(metric: Metric[Gauge, Settings.ForValueInstrument], - instruments: Seq[Instrument.Snapshot[Double]]): MetricSnapshot.Values[Double] = + override protected def buildMetricSnapshot( + metric: Metric[Gauge, Settings.ForValueInstrument], + instruments: Seq[Instrument.Snapshot[Double]] + ): MetricSnapshot.Values[Double] = MetricSnapshot.ofValues(metric.name, metric.description, metric.settings, instruments) } } @@ -101,27 +122,40 @@ class MetricFactory private ( /** * Creates a new histogram-based metric, backed by the Histogram.Atomic implementation. */ - def histogram(name: String, description: Option[String], unit: Option[MeasurementUnit], dynamicRange: Option[DynamicRange], - autoUpdateInterval: Option[Duration]): BaseMetric[Histogram, Metric.Settings.ForDistributionInstrument, Distribution] with Metric.Histogram = { + def histogram( + name: String, + description: Option[String], + unit: Option[MeasurementUnit], + dynamicRange: Option[DynamicRange], + autoUpdateInterval: Option[Duration] + ): BaseMetric[Histogram, Metric.Settings.ForDistributionInstrument, Distribution] with Metric.Histogram = { val metricDescription = description.getOrElse("") - val metricSettings = Metric.Settings.ForDistributionInstrument ( + val metricSettings = Metric.Settings.ForDistributionInstrument( unit.getOrElse(defaultHistogramSettings.unit), resolveAutoUpdateInterval(name, autoUpdateInterval, defaultHistogramSettings.autoUpdateInterval), resolveDynamicRange(name, dynamicRange, defaultHistogramSettings.dynamicRange) ) - val builder = (metric: BaseMetric[Histogram, Metric.Settings.ForDistributionInstrument, Distribution], tags: TagSet) => - new Histogram.Atomic(metric, tags, metricSettings.dynamicRange) + val builder = + (metric: BaseMetric[Histogram, Metric.Settings.ForDistributionInstrument, Distribution], tags: TagSet) => + new Histogram.Atomic(metric, tags, metricSettings.dynamicRange) - new BaseMetric[Histogram, Metric.Settings.ForDistributionInstrument, Distribution](name, metricDescription, metricSettings, - builder, scheduler) with Metric.Histogram { + new BaseMetric[Histogram, Metric.Settings.ForDistributionInstrument, Distribution]( + name, + metricDescription, + metricSettings, + builder, + scheduler + ) with Metric.Histogram { override protected def instrumentType: Instrument.Type = Instrument.Type.Histogram - override protected def buildMetricSnapshot(metric: Metric[Histogram, Settings.ForDistributionInstrument], - instruments: Seq[Instrument.Snapshot[Distribution]]): MetricSnapshot.Distributions = + override protected def buildMetricSnapshot( + metric: Metric[Histogram, Settings.ForDistributionInstrument], + instruments: Seq[Instrument.Snapshot[Distribution]] + ): MetricSnapshot.Distributions = MetricSnapshot.ofDistributions(metric.name, metric.description, metric.settings, instruments) } } @@ -129,11 +163,16 @@ class MetricFactory private ( /** * Creates a new histogram-based metric, backed by the Histogram.Atomic implementation. */ - def timer(name: String, description: Option[String], unit: Option[MeasurementUnit], dynamicRange: Option[DynamicRange], - autoUpdateInterval: Option[Duration]): BaseMetric[Timer, Metric.Settings.ForDistributionInstrument, Distribution] with Metric.Timer = { + def timer( + name: String, + description: Option[String], + unit: Option[MeasurementUnit], + dynamicRange: Option[DynamicRange], + autoUpdateInterval: Option[Duration] + ): BaseMetric[Timer, Metric.Settings.ForDistributionInstrument, Distribution] with Metric.Timer = { val metricDescription = description.getOrElse("") - val metricSettings = Metric.Settings.ForDistributionInstrument ( + val metricSettings = Metric.Settings.ForDistributionInstrument( unit.getOrElse(defaultTimerSettings.unit), resolveAutoUpdateInterval(name, autoUpdateInterval, defaultTimerSettings.autoUpdateInterval), resolveDynamicRange(name, dynamicRange, defaultTimerSettings.dynamicRange) @@ -142,14 +181,21 @@ class MetricFactory private ( val builder = (metric: BaseMetric[Timer, Metric.Settings.ForDistributionInstrument, Distribution], tags: TagSet) => new Timer.Atomic(metric, tags, metricSettings.dynamicRange, clock) - new BaseMetric[Timer, Metric.Settings.ForDistributionInstrument, Distribution](name, metricDescription, metricSettings, - builder, scheduler) with Metric.Timer { + new BaseMetric[Timer, Metric.Settings.ForDistributionInstrument, Distribution]( + name, + metricDescription, + metricSettings, + builder, + scheduler + ) with Metric.Timer { override protected def instrumentType: Instrument.Type = Instrument.Type.Timer - override protected def buildMetricSnapshot(metric: Metric[Timer, Settings.ForDistributionInstrument], - instruments: Seq[Instrument.Snapshot[Distribution]]): MetricSnapshot.Distributions = + override protected def buildMetricSnapshot( + metric: Metric[Timer, Settings.ForDistributionInstrument], + instruments: Seq[Instrument.Snapshot[Distribution]] + ): MetricSnapshot.Distributions = MetricSnapshot.ofDistributions(metric.name, metric.description, metric.settings, instruments) } } @@ -157,42 +203,63 @@ class MetricFactory private ( /** * Creates a new histogram-based metric, backed by the Histogram.Atomic implementation. */ - def rangeSampler(name: String, description: Option[String], unit: Option[MeasurementUnit], dynamicRange: Option[DynamicRange], - autoUpdateInterval: Option[Duration]): BaseMetric[RangeSampler, Metric.Settings.ForDistributionInstrument, Distribution] with Metric.RangeSampler = { + def rangeSampler( + name: String, + description: Option[String], + unit: Option[MeasurementUnit], + dynamicRange: Option[DynamicRange], + autoUpdateInterval: Option[Duration] + ): BaseMetric[RangeSampler, Metric.Settings.ForDistributionInstrument, Distribution] with Metric.RangeSampler = { val metricDescription = description.getOrElse("") - val metricSettings = Metric.Settings.ForDistributionInstrument ( + val metricSettings = Metric.Settings.ForDistributionInstrument( unit.getOrElse(defaultRangeSamplerSettings.unit), resolveAutoUpdateInterval(name, autoUpdateInterval, defaultRangeSamplerSettings.autoUpdateInterval), resolveDynamicRange(name, dynamicRange, defaultRangeSamplerSettings.dynamicRange) ) - val builder = (metric: BaseMetric[RangeSampler, Metric.Settings.ForDistributionInstrument, Distribution], tags: TagSet) => - new RangeSampler.Atomic(metric, tags, metricSettings.dynamicRange) + val builder = + (metric: BaseMetric[RangeSampler, Metric.Settings.ForDistributionInstrument, Distribution], tags: TagSet) => + new RangeSampler.Atomic(metric, tags, metricSettings.dynamicRange) - new BaseMetric[RangeSampler, Metric.Settings.ForDistributionInstrument, Distribution](name, metricDescription, metricSettings, - builder, scheduler) with Metric.RangeSampler { + new BaseMetric[RangeSampler, Metric.Settings.ForDistributionInstrument, Distribution]( + name, + metricDescription, + metricSettings, + builder, + scheduler + ) with Metric.RangeSampler { override protected def instrumentType: Instrument.Type = Instrument.Type.RangeSampler - override protected def buildMetricSnapshot(metric: Metric[RangeSampler, Settings.ForDistributionInstrument], - instruments: Seq[Instrument.Snapshot[Distribution]]): MetricSnapshot.Distributions = + override protected def buildMetricSnapshot( + metric: Metric[RangeSampler, Settings.ForDistributionInstrument], + instruments: Seq[Instrument.Snapshot[Distribution]] + ): MetricSnapshot.Distributions = MetricSnapshot.ofDistributions(metric.name, metric.description, metric.settings, instruments) } } - private def resolveAutoUpdateInterval(metricName: String, codeOption: Option[Duration], defaultValue: Duration): Duration = { + private def resolveAutoUpdateInterval( + metricName: String, + codeOption: Option[Duration], + defaultValue: Duration + ): Duration = { customSettings.get(metricName) .flatMap(_.autoUpdateInterval) .getOrElse(codeOption.getOrElse(defaultValue)) } - private def resolveDynamicRange(metricName: String, codeDynamicRange: Option[DynamicRange], default: DynamicRange): DynamicRange = { + private def resolveDynamicRange( + metricName: String, + codeDynamicRange: Option[DynamicRange], + default: DynamicRange + ): DynamicRange = { val overrides = customSettings.get(metricName) val base = codeDynamicRange.getOrElse(default) - DynamicRange ( + DynamicRange( lowestDiscernibleValue = overrides.flatMap(_.lowestDiscernibleValue).getOrElse(base.lowestDiscernibleValue), highestTrackableValue = overrides.flatMap(_.highestTrackableValue).getOrElse(base.highestTrackableValue), significantValueDigits = overrides.flatMap(_.significantValueDigits).getOrElse(base.significantValueDigits) @@ -204,29 +271,29 @@ object MetricFactory { def from(config: Config, clock: Clock, scheduler: Option[ScheduledExecutorService]): MetricFactory = { val factoryConfig = config.getConfig("kamon.metric.factory") - val defaultCounterSettings = Metric.Settings.ForValueInstrument ( + val defaultCounterSettings = Metric.Settings.ForValueInstrument( MeasurementUnit.none, factoryConfig.getDuration("default-settings.counter.auto-update-interval") ) - val defaultGaugeSettings = Metric.Settings.ForValueInstrument ( + val defaultGaugeSettings = Metric.Settings.ForValueInstrument( MeasurementUnit.none, factoryConfig.getDuration("default-settings.gauge.auto-update-interval") ) - val defaultHistogramSettings = Metric.Settings.ForDistributionInstrument ( + val defaultHistogramSettings = Metric.Settings.ForDistributionInstrument( MeasurementUnit.none, factoryConfig.getDuration("default-settings.histogram.auto-update-interval"), readDynamicRange(factoryConfig.getConfig("default-settings.histogram")) ) - val defaultTimerSettings = Metric.Settings.ForDistributionInstrument ( + val defaultTimerSettings = Metric.Settings.ForDistributionInstrument( MeasurementUnit.none, factoryConfig.getDuration("default-settings.timer.auto-update-interval"), readDynamicRange(factoryConfig.getConfig("default-settings.timer")) ) - val defaultRangeSamplerSettings = Metric.Settings.ForDistributionInstrument ( + val defaultRangeSamplerSettings = Metric.Settings.ForDistributionInstrument( MeasurementUnit.none, factoryConfig.getDuration("default-settings.range-sampler.auto-update-interval"), readDynamicRange(factoryConfig.getConfig("default-settings.range-sampler")) @@ -237,8 +304,16 @@ object MetricFactory { .filter(nonEmptySection) .map(readCustomSettings) - new MetricFactory(defaultCounterSettings, defaultGaugeSettings, defaultHistogramSettings, defaultTimerSettings, - defaultRangeSamplerSettings, customSettings, clock, scheduler) + new MetricFactory( + defaultCounterSettings, + defaultGaugeSettings, + defaultHistogramSettings, + defaultTimerSettings, + defaultRangeSamplerSettings, + customSettings, + clock, + scheduler + ) } private def nonEmptySection(entry: (String, Config)): Boolean = entry match { @@ -248,10 +323,14 @@ object MetricFactory { private def readCustomSettings(entry: (String, Config)): (String, CustomSettings) = { val (metricName, metricConfig) = entry val customSettings = CustomSettings( - if (metricConfig.hasPath("auto-update-interval")) Some(metricConfig.getDuration("auto-update-interval")) else None, - if (metricConfig.hasPath("lowest-discernible-value")) Some(metricConfig.getLong("lowest-discernible-value")) else None, - if (metricConfig.hasPath("highest-trackable-value")) Some(metricConfig.getLong("highest-trackable-value")) else None, - if (metricConfig.hasPath("significant-value-digits")) Some(metricConfig.getInt("significant-value-digits")) else None + if (metricConfig.hasPath("auto-update-interval")) Some(metricConfig.getDuration("auto-update-interval")) + else None, + if (metricConfig.hasPath("lowest-discernible-value")) Some(metricConfig.getLong("lowest-discernible-value")) + else None, + if (metricConfig.hasPath("highest-trackable-value")) Some(metricConfig.getLong("highest-trackable-value")) + else None, + if (metricConfig.hasPath("significant-value-digits")) Some(metricConfig.getInt("significant-value-digits")) + else None ) metricName -> customSettings } @@ -263,10 +342,10 @@ object MetricFactory { significantValueDigits = config.getInt("significant-value-digits") ) - private case class CustomSettings ( + private case class CustomSettings( autoUpdateInterval: Option[Duration], lowestDiscernibleValue: Option[Long], highestTrackableValue: Option[Long], significantValueDigits: Option[Int] ) -} \ No newline at end of file +} diff --git a/core/kamon-core/src/main/scala/kamon/metric/MetricRegistry.scala b/core/kamon-core/src/main/scala/kamon/metric/MetricRegistry.scala index 569066805..f763ad619 100644 --- a/core/kamon-core/src/main/scala/kamon/metric/MetricRegistry.scala +++ b/core/kamon-core/src/main/scala/kamon/metric/MetricRegistry.scala @@ -42,16 +42,19 @@ class MetricRegistry(config: Config, clock: Clock) { @volatile private var _scheduler: Option[ScheduledExecutorService] = None @volatile private var _factory: MetricFactory = MetricFactory.from(config, clock, _scheduler) - /** * Retrieves or registers a new counter-based metric. */ - def counter(name: String, description: Option[String], unit: Option[MeasurementUnit], autoUpdateInterval: Option[Duration]): - Metric.Counter = { + def counter( + name: String, + description: Option[String], + unit: Option[MeasurementUnit], + autoUpdateInterval: Option[Duration] + ): Metric.Counter = { val metric = validateInstrumentType[Metric.Counter] { _metrics.getOrElseUpdate(name, _factory.counter(name, description, unit, autoUpdateInterval)) - } (name, Instrument.Type.Counter) + }(name, Instrument.Type.Counter) checkDescription(metric.name, metric.description, description) checkUnit(metric.name, metric.settings.unit, unit) @@ -62,12 +65,16 @@ class MetricRegistry(config: Config, clock: Clock) { /** * Retrieves or registers a new gauge-based metric. */ - def gauge(name: String, description: Option[String], unit: Option[MeasurementUnit], autoUpdateInterval: Option[Duration]): - Metric.Gauge = { + def gauge( + name: String, + description: Option[String], + unit: Option[MeasurementUnit], + autoUpdateInterval: Option[Duration] + ): Metric.Gauge = { val metric = validateInstrumentType[Metric.Gauge] { _metrics.getOrElseUpdate(name, _factory.gauge(name, description, unit, autoUpdateInterval)) - } (name, Instrument.Type.Gauge) + }(name, Instrument.Type.Gauge) checkDescription(metric.name, metric.description, description) checkUnit(metric.name, metric.settings.unit, unit) @@ -78,12 +85,17 @@ class MetricRegistry(config: Config, clock: Clock) { /** * Retrieves or registers a new histogram-based metric. */ - def histogram(name: String, description: Option[String], unit: Option[MeasurementUnit], dynamicRange: Option[DynamicRange], - autoUpdateInterval: Option[Duration]): Metric.Histogram = { + def histogram( + name: String, + description: Option[String], + unit: Option[MeasurementUnit], + dynamicRange: Option[DynamicRange], + autoUpdateInterval: Option[Duration] + ): Metric.Histogram = { val metric = validateInstrumentType[Metric.Histogram] { _metrics.getOrElseUpdate(name, _factory.histogram(name, description, unit, dynamicRange, autoUpdateInterval)) - } (name, Instrument.Type.Histogram) + }(name, Instrument.Type.Histogram) checkDescription(metric.name, metric.description, description) checkUnit(metric.name, metric.settings.unit, unit) @@ -95,12 +107,19 @@ class MetricRegistry(config: Config, clock: Clock) { /** * Retrieves or registers a new timer-based metric. */ - def timer(name: String, description: Option[String], dynamicRange: Option[DynamicRange], autoUpdateInterval: Option[Duration]): Metric.Timer = { + def timer( + name: String, + description: Option[String], + dynamicRange: Option[DynamicRange], + autoUpdateInterval: Option[Duration] + ): Metric.Timer = { val metric = validateInstrumentType[Metric.Timer] { - _metrics.getOrElseUpdate(name, _factory.timer(name, description, Some(MeasurementUnit.time.nanoseconds), - dynamicRange, autoUpdateInterval)) - } (name, Instrument.Type.Timer) + _metrics.getOrElseUpdate( + name, + _factory.timer(name, description, Some(MeasurementUnit.time.nanoseconds), dynamicRange, autoUpdateInterval) + ) + }(name, Instrument.Type.Timer) checkDescription(metric.name, metric.description, description) checkDynamicRange(metric.name, metric.settings.dynamicRange, dynamicRange) @@ -111,12 +130,17 @@ class MetricRegistry(config: Config, clock: Clock) { /** * Retrieves or registers a new range sampler-based metric. */ - def rangeSampler(name: String, description: Option[String], unit: Option[MeasurementUnit], dynamicRange: Option[DynamicRange], - autoUpdateInterval: Option[Duration]): Metric.RangeSampler = { + def rangeSampler( + name: String, + description: Option[String], + unit: Option[MeasurementUnit], + dynamicRange: Option[DynamicRange], + autoUpdateInterval: Option[Duration] + ): Metric.RangeSampler = { val metric = validateInstrumentType[Metric.RangeSampler] { _metrics.getOrElseUpdate(name, _factory.rangeSampler(name, description, unit, dynamicRange, autoUpdateInterval)) - } (name, Instrument.Type.RangeSampler) + }(name, Instrument.Type.RangeSampler) checkDescription(metric.name, metric.description, description) checkUnit(metric.name, metric.settings.unit, unit) @@ -145,7 +169,7 @@ class MetricRegistry(config: Config, clock: Clock) { private def validateInstrumentType[T](metric: => Metric[_, _])(name: String, instrumentType: Instrument.Type): T = { val lookedUpMetric = metric - if(instrumentType.implementation.isInstance(lookedUpMetric)) + if (instrumentType.implementation.isInstance(lookedUpMetric)) lookedUpMetric.asInstanceOf[T] else throw new IllegalArgumentException( @@ -163,27 +187,37 @@ class MetricRegistry(config: Config, clock: Clock) { } private def checkInstrumentType(name: String, instrumentType: Instrument.Type, metric: Metric[_, _]): Unit = - if(!instrumentType.implementation.isInstance(metric)) - sys.error(s"Cannot redefine metric [$name] as a [${instrumentType.name}], it was already registered as a [${metric.getClass.getName}]") + if (!instrumentType.implementation.isInstance(metric)) + sys.error( + s"Cannot redefine metric [$name] as a [${instrumentType.name}], it was already registered as a [${metric.getClass.getName}]" + ) private def checkDescription(name: String, description: String, providedDescription: Option[String]): Unit = - if(providedDescription.exists(d => d != description)) + if (providedDescription.exists(d => d != description)) _logger.warn(s"Ignoring new description [${providedDescription.getOrElse("")}] for metric [${name}]") private def checkUnit(name: String, unit: MeasurementUnit, providedUnit: Option[MeasurementUnit]): Unit = - if(providedUnit.exists(u => u != unit)) + if (providedUnit.exists(u => u != unit)) _logger.warn(s"Ignoring new unit [${providedUnit.getOrElse("")}] for metric [${name}]") - private def checkAutoUpdate(name: String, autoUpdateInterval: Duration, providedAutoUpdateInterval: Option[Duration]): Unit = - if(providedAutoUpdateInterval.exists(u => u != autoUpdateInterval)) - _logger.warn(s"Ignoring new auto-update interval [${providedAutoUpdateInterval.getOrElse("")}] for metric [${name}]") + private def checkAutoUpdate( + name: String, + autoUpdateInterval: Duration, + providedAutoUpdateInterval: Option[Duration] + ): Unit = + if (providedAutoUpdateInterval.exists(u => u != autoUpdateInterval)) + _logger.warn( + s"Ignoring new auto-update interval [${providedAutoUpdateInterval.getOrElse("")}] for metric [${name}]" + ) - private def checkDynamicRange(name: String, dynamicRange: DynamicRange, providedDynamicRange: Option[DynamicRange]): Unit = - if(providedDynamicRange.exists(dr => dr != dynamicRange)) + private def checkDynamicRange( + name: String, + dynamicRange: DynamicRange, + providedDynamicRange: Option[DynamicRange] + ): Unit = + if (providedDynamicRange.exists(dr => dr != dynamicRange)) _logger.warn(s"Ignoring new dynamic range [${providedDynamicRange.getOrElse("")}] for metric [${name}]") - - /** * Creates a period snapshot of all metrics contained in this registry. The period always starts at the instant of * the last snapshot taken in which the state was reset and until the current instant. The special case of the first @@ -198,12 +232,15 @@ class MetricRegistry(config: Config, clock: Clock) { _metrics.foreach { case (_, metric) => metric match { - case m: Metric.Counter => counters = m.snapshot(resetState).asInstanceOf[MetricSnapshot.Values[Long]] :: counters - case m: Metric.Gauge => gauges = m.snapshot(resetState).asInstanceOf[MetricSnapshot.Values[Double]] :: gauges - case m: Metric.Histogram => histograms = m.snapshot(resetState).asInstanceOf[MetricSnapshot.Distributions] :: histograms - case m: Metric.Timer => timers = m.snapshot(resetState).asInstanceOf[MetricSnapshot.Distributions] :: timers - case m: Metric.RangeSampler => rangeSamplers = m.snapshot(resetState).asInstanceOf[MetricSnapshot.Distributions] :: rangeSamplers - } + case m: Metric.Counter => + counters = m.snapshot(resetState).asInstanceOf[MetricSnapshot.Values[Long]] :: counters + case m: Metric.Gauge => gauges = m.snapshot(resetState).asInstanceOf[MetricSnapshot.Values[Double]] :: gauges + case m: Metric.Histogram => + histograms = m.snapshot(resetState).asInstanceOf[MetricSnapshot.Distributions] :: histograms + case m: Metric.Timer => timers = m.snapshot(resetState).asInstanceOf[MetricSnapshot.Distributions] :: timers + case m: Metric.RangeSampler => + rangeSamplers = m.snapshot(resetState).asInstanceOf[MetricSnapshot.Distributions] :: rangeSamplers + } } val periodStart = _lastSnapshotInstant diff --git a/core/kamon-core/src/main/scala/kamon/metric/MetricSnapshot.scala b/core/kamon-core/src/main/scala/kamon/metric/MetricSnapshot.scala index cdbf916ac..a228fee82 100644 --- a/core/kamon-core/src/main/scala/kamon/metric/MetricSnapshot.scala +++ b/core/kamon-core/src/main/scala/kamon/metric/MetricSnapshot.scala @@ -17,12 +17,11 @@ package kamon package metric - /** * Contains snapshots of all known instruments for a given metric. Instances of this class are meant to be exposed to * metric reporters via the PeriodSnapshot. */ -case class MetricSnapshot[Sett <: Metric.Settings, Snap] ( +case class MetricSnapshot[Sett <: Metric.Settings, Snap]( name: String, description: String, settings: Sett, @@ -37,8 +36,12 @@ object MetricSnapshot { /** * Creates a MetricSnapshot instance for metrics that produce single values. */ - def ofValues[T](name: String, description: String, settings: Metric.Settings.ForValueInstrument, - instruments: Seq[Instrument.Snapshot[T]]): Values[T] = { + def ofValues[T]( + name: String, + description: String, + settings: Metric.Settings.ForValueInstrument, + instruments: Seq[Instrument.Snapshot[T]] + ): Values[T] = { MetricSnapshot( name, @@ -51,8 +54,12 @@ object MetricSnapshot { /** * Creates a MetricSnapshot instance for metrics that produce distributions. */ - def ofDistributions(name: String, description: String, settings: Metric.Settings.ForDistributionInstrument, - instruments: Seq[Instrument.Snapshot[Distribution]]): Distributions = { + def ofDistributions( + name: String, + description: String, + settings: Metric.Settings.ForDistributionInstrument, + instruments: Seq[Instrument.Snapshot[Distribution]] + ): Distributions = { MetricSnapshot( name, @@ -61,4 +68,4 @@ object MetricSnapshot { instruments ) } -} \ No newline at end of file +} diff --git a/core/kamon-core/src/main/scala/kamon/metric/PeriodSnapshot.scala b/core/kamon-core/src/main/scala/kamon/metric/PeriodSnapshot.scala index 4868e308d..0aa7a8132 100644 --- a/core/kamon-core/src/main/scala/kamon/metric/PeriodSnapshot.scala +++ b/core/kamon-core/src/main/scala/kamon/metric/PeriodSnapshot.scala @@ -27,7 +27,7 @@ import scala.collection.mutable /** * Contains immutable snapshots of all metrics and the values recorded on their instruments for a given period of time. */ -case class PeriodSnapshot ( +case class PeriodSnapshot( from: Instant, to: Instant, counters: Seq[MetricSnapshot.Values[Long]], @@ -52,7 +52,6 @@ object PeriodSnapshot { def accumulator(period: Duration, margin: Duration, stalePeriod: Duration): PeriodSnapshot.Accumulator = new PeriodSnapshot.Accumulator(period, margin, stalePeriod) - /** * Accumulates PeriodSnapshot instances over the specified period of time and produces a single PeriodSnapshot that * merges all metrics and instruments accumulated during that period. This class contains mutable state, is not @@ -99,12 +98,14 @@ object PeriodSnapshot { def add(periodSnapshot: PeriodSnapshot): Option[PeriodSnapshot] = { // Initialize the next tick based on incoming snapshots. - if(_nextTick == Instant.EPOCH) + if (_nextTick == Instant.EPOCH) _nextTick = Clock.nextAlignedInstant(periodSnapshot.to, period) // short-circuit if there is no need to accumulate (e.g. when metrics tick-interval is the same as duration or the // snapshots have a longer period than the duration). - if(isSameDurationAsTickInterval() || (isAroundNextTick(periodSnapshot.to) && _accumulatingFrom.isEmpty)) Some(periodSnapshot) else { + if (isSameDurationAsTickInterval() || (isAroundNextTick(periodSnapshot.to) && _accumulatingFrom.isEmpty)) + Some(periodSnapshot) + else { if (_accumulatingFrom.isEmpty) _accumulatingFrom = Some(periodSnapshot.from) @@ -114,7 +115,7 @@ object PeriodSnapshot { periodSnapshot.timers.foreach(t => accumulateDistribution(periodSnapshot.to, _timers, t)) periodSnapshot.rangeSamplers.foreach(rs => accumulateDistribution(periodSnapshot.to, _rangeSamplers, rs)) - for(from <- _accumulatingFrom if isAroundNextTick(periodSnapshot.to)) yield { + for (from <- _accumulatingFrom if isAroundNextTick(periodSnapshot.to)) yield { val accumulatedPeriodSnapshot = buildPeriodSnapshot(from, periodSnapshot.to, resetState = true) _nextTick = Clock.nextAlignedInstant(_nextTick, period) _accumulatingFrom = None @@ -140,7 +141,9 @@ object PeriodSnapshot { private def buildPeriodSnapshot(from: Instant, to: Instant, resetState: Boolean): PeriodSnapshot = { cleanStaleEntries(to) - val snapshot = PeriodSnapshot(from, to, + val snapshot = PeriodSnapshot( + from, + to, counters = valueSnapshots(_counters), gauges = valueSnapshots(_gauges), histograms = distributionSnapshots(_histograms), @@ -148,7 +151,7 @@ object PeriodSnapshot { rangeSamplers = distributionSnapshots(_rangeSamplers) ) - if(resetState) + if (resetState) clearAccumulatedData() snapshot @@ -158,7 +161,7 @@ object PeriodSnapshot { var metrics = List.empty[MetricSnapshot.Values[T]] storage.foreach { case (_, metricEntry) => - val snapshot = MetricSnapshot.ofValues ( + val snapshot = MetricSnapshot.ofValues( metricEntry.snapshot.name, metricEntry.snapshot.description, metricEntry.snapshot.settings, @@ -175,7 +178,7 @@ object PeriodSnapshot { var metrics = List.empty[MetricSnapshot.Distributions] storage.foreach { case (_, metricEntry) => - val snapshot = MetricSnapshot.ofDistributions ( + val snapshot = MetricSnapshot.ofDistributions( metricEntry.snapshot.name, metricEntry.snapshot.description, metricEntry.snapshot.settings, @@ -188,24 +191,40 @@ object PeriodSnapshot { metrics } - private def accumulateValue(currentInstant: Instant, storage: ValueMetricStorage[Long], current: MetricSnapshot.Values[Long]): Unit = + private def accumulateValue( + currentInstant: Instant, + storage: ValueMetricStorage[Long], + current: MetricSnapshot.Values[Long] + ): Unit = accumulate(currentInstant, storage, current)(_ + _) - private def keepLastValue(currentInstant: Instant, storage: ValueMetricStorage[Double], current: MetricSnapshot.Values[Double]): Unit = + private def keepLastValue( + currentInstant: Instant, + storage: ValueMetricStorage[Double], + current: MetricSnapshot.Values[Double] + ): Unit = accumulate(currentInstant, storage, current)((c, _) => c) - private def accumulateDistribution(currentInstant: Instant, storage: DistributionMetricStorage, current: MetricSnapshot.Distributions): Unit = + private def accumulateDistribution( + currentInstant: Instant, + storage: DistributionMetricStorage, + current: MetricSnapshot.Distributions + ): Unit = accumulate(currentInstant, storage, current)(Distribution.merge) - private def accumulate[IS, MS <: Metric.Settings](currentInstant: Instant, storage: mutable.Map[String, MetricEntry[MS, IS]], - current: MetricSnapshot[MS, IS])(combine: (IS, IS) => IS): Unit = { + private def accumulate[IS, MS <: Metric.Settings]( + currentInstant: Instant, + storage: mutable.Map[String, MetricEntry[MS, IS]], + current: MetricSnapshot[MS, IS] + )(combine: (IS, IS) => IS): Unit = { storage.get(current.name) match { case None => // If the metric is not present just register it val instruments = mutable.Map.newBuilder[TagSet, InstrumentEntry[IS]] current.instruments.foreach { - case Instrument.Snapshot(tags, snapshot) => instruments += (tags -> InstrumentEntry(snapshot, currentInstant)) + case Instrument.Snapshot(tags, snapshot) => + instruments += (tags -> InstrumentEntry(snapshot, currentInstant)) } storage.put(current.name, MetricEntry[MS, IS](current, instruments.result())) @@ -232,9 +251,11 @@ object PeriodSnapshot { def clean[A <: Metric.Settings, B](store: mutable.Map[String, MetricEntry[A, B]]): Unit = { // Removes all stale instruments - store.foreach { case (_, metricEntry) => metricEntry.instruments.retain { - case (_, instrumentEntry) => instrumentEntry.lastSeen.isAfter(cutoff) - }} + store.foreach { case (_, metricEntry) => + metricEntry.instruments.retain { + case (_, instrumentEntry) => instrumentEntry.lastSeen.isAfter(cutoff) + } + } // Removes all metrics that don't have any instruments left store.retain { case (_, metricEntry) => metricEntry.instruments.nonEmpty } @@ -256,14 +277,15 @@ object PeriodSnapshot { } private type ValueMetricStorage[T] = mutable.Map[String, MetricEntry[Metric.Settings.ForValueInstrument, T]] - private type DistributionMetricStorage = mutable.Map[String, MetricEntry[Metric.Settings.ForDistributionInstrument, Distribution]] + private type DistributionMetricStorage = + mutable.Map[String, MetricEntry[Metric.Settings.ForDistributionInstrument, Distribution]] - private case class MetricEntry[Sett <: Metric.Settings, Snap] ( + private case class MetricEntry[Sett <: Metric.Settings, Snap]( snapshot: MetricSnapshot[Sett, Snap], instruments: mutable.Map[TagSet, InstrumentEntry[Snap]] ) - private case class InstrumentEntry[Snap] ( + private case class InstrumentEntry[Snap]( var snapshot: Snap, var lastSeen: Instant ) diff --git a/core/kamon-core/src/main/scala/kamon/metric/RangeSampler.scala b/core/kamon-core/src/main/scala/kamon/metric/RangeSampler.scala index 7d955ad90..d14a3e8d2 100644 --- a/core/kamon-core/src/main/scala/kamon/metric/RangeSampler.scala +++ b/core/kamon-core/src/main/scala/kamon/metric/RangeSampler.scala @@ -26,7 +26,6 @@ import org.slf4j.LoggerFactory import scala.annotation.tailrec - /** * Instrument that tracks the behavior of a variable that can increase and decrease over time. A range sampler keeps * track of the observed minimum and maximum values for the tracked variable and is constantly recording and resetting @@ -71,7 +70,6 @@ trait RangeSampler extends Instrument[RangeSampler, Metric.Settings.ForDistribut } - object RangeSampler { private val _logger = LoggerFactory.getLogger(classOf[RangeSampler]) @@ -81,8 +79,11 @@ object RangeSampler { * and updated concurrently. This is, in fact, a close copy of the Histogram.Atomic implementation, modified to match * the Timer interface. */ - class Atomic(val metric: BaseMetric[RangeSampler, Metric.Settings.ForDistributionInstrument, Distribution], - val tags: TagSet, val dynamicRange: DynamicRange) extends BaseAtomicHdrHistogram(dynamicRange) with RangeSampler + class Atomic( + val metric: BaseMetric[RangeSampler, Metric.Settings.ForDistributionInstrument, Distribution], + val tags: TagSet, + val dynamicRange: DynamicRange + ) extends BaseAtomicHdrHistogram(dynamicRange) with RangeSampler with Instrument.Snapshotting[Distribution] with DistributionSnapshotBuilder with BaseMetricAutoUpdate[RangeSampler, Metric.Settings.ForDistributionInstrument, Distribution] { @@ -143,7 +144,7 @@ object RangeSampler { } catch { case _: ArrayIndexOutOfBoundsException => - _logger.warn ( + _logger.warn( s"Failed to record value on [${metric.name},${tags}] because the value is outside of the " + "configured range. You might need to change your dynamic range configuration for this metric" ) @@ -155,21 +156,19 @@ object RangeSampler { override protected def baseMetric: BaseMetric[RangeSampler, Settings.ForDistributionInstrument, Distribution] = metric - /** * Keeps track of the max value of an observed value using an AtomicLong as the underlying storage. */ private class AtomicLongMaxUpdater(value: AtomicLong) { - def update(newMax: Long):Unit = { + def update(newMax: Long): Unit = { @tailrec def compare(): Long = { val currentMax = value.get() - if(newMax > currentMax) { + if (newMax > currentMax) { if (!value.compareAndSet(currentMax, newMax)) { compare() } else newMax - } - else currentMax + } else currentMax } compare() } diff --git a/core/kamon-core/src/main/scala/kamon/metric/Tagging.scala b/core/kamon-core/src/main/scala/kamon/metric/Tagging.scala index 509046c91..2f7afc1d6 100644 --- a/core/kamon-core/src/main/scala/kamon/metric/Tagging.scala +++ b/core/kamon-core/src/main/scala/kamon/metric/Tagging.scala @@ -47,4 +47,4 @@ trait Tagging[I] { * Returns an instrument with additional tags from the provided TagSet. */ def withTags(tags: TagSet): I -} \ No newline at end of file +} diff --git a/core/kamon-core/src/main/scala/kamon/metric/Timer.scala b/core/kamon-core/src/main/scala/kamon/metric/Timer.scala index a756053d8..62e206aa1 100644 --- a/core/kamon-core/src/main/scala/kamon/metric/Timer.scala +++ b/core/kamon-core/src/main/scala/kamon/metric/Timer.scala @@ -26,7 +26,6 @@ import kamon.util.Clock import org.HdrHistogram.BaseAtomicHdrHistogram import org.slf4j.LoggerFactory - /** * Instrument that tracks the distribution of latency values within a configured range and precision. Timers are just a * special case of histograms that provide special APIs dedicated to recording latency measurements. @@ -62,7 +61,6 @@ trait Timer extends Instrument[Timer, Metric.Settings.ForDistributionInstrument] } - object Timer { private val _logger = LoggerFactory.getLogger(classOf[Timer]) @@ -79,16 +77,19 @@ object Timer { } - /** * Timer implementation with thread safety guarantees. Instances of this class can be safely shared across threads * and updated concurrently. This is, in fact, a close copy of the Histogram.Atomic implementation, modified to match * the Timer interface. */ - class Atomic(val metric: BaseMetric[Timer, Metric.Settings.ForDistributionInstrument, Distribution], - val tags: TagSet, val dynamicRange: DynamicRange, clock: Clock) extends BaseAtomicHdrHistogram(dynamicRange) with Timer - with Instrument.Snapshotting[Distribution] with DistributionSnapshotBuilder - with BaseMetricAutoUpdate[Timer, Metric.Settings.ForDistributionInstrument, Distribution] { + class Atomic( + val metric: BaseMetric[Timer, Metric.Settings.ForDistributionInstrument, Distribution], + val tags: TagSet, + val dynamicRange: DynamicRange, + clock: Clock + ) extends BaseAtomicHdrHistogram(dynamicRange) with Timer + with Instrument.Snapshotting[Distribution] with DistributionSnapshotBuilder + with BaseMetricAutoUpdate[Timer, Metric.Settings.ForDistributionInstrument, Distribution] { /** Starts a timer that will record the elapsed time between the start and stop instants */ override def start(): Started = @@ -103,7 +104,7 @@ object Timer { val highestTrackableValue = getHighestTrackableValue() recordValue(highestTrackableValue) - _logger.warn ( + _logger.warn( s"Failed to record value [$nanos] on [${metric.name},${tags}] because the value is outside of the " + s"configured range. The recorded value was adjusted to the highest trackable value [$highestTrackableValue]. " + "You might need to change your dynamic range configuration for this metric" @@ -125,7 +126,6 @@ object Timer { metric } - /** * Started timer implementation that allows applying tags before the timer is stopped. */ @@ -145,10 +145,10 @@ object Timer { new TaggableStartedTimer(startedAt, clock, instrument.withTags(tags)) override def stop(): Unit = synchronized { - if(!stopped) { + if (!stopped) { instrument.record(clock.nanosSince(startedAt)) stopped = true } } } -} \ No newline at end of file +} diff --git a/core/kamon-core/src/main/scala/kamon/module/MetricReporter.scala b/core/kamon-core/src/main/scala/kamon/module/MetricReporter.scala index 07fd9d1c8..0aea817a1 100644 --- a/core/kamon-core/src/main/scala/kamon/module/MetricReporter.scala +++ b/core/kamon-core/src/main/scala/kamon/module/MetricReporter.scala @@ -42,16 +42,18 @@ object MetricReporter { * the period snapshots sent the provided reporter in the same order they are provided to this method. */ def withTransformations(reporter: MetricReporter, transformations: Transformation*): MetricReporter = - new Module.Wrapped with MetricReporter { + new Module.Wrapped with MetricReporter { - override def stop(): Unit = reporter.stop() - override def reconfigure(newConfig: Config): Unit = reporter.reconfigure(newConfig) - override def originalClass: Class[_ <: Module] = reporter.getClass + override def stop(): Unit = reporter.stop() + override def reconfigure(newConfig: Config): Unit = reporter.reconfigure(newConfig) + override def originalClass: Class[_ <: Module] = reporter.getClass - override def reportPeriodSnapshot(snapshot: PeriodSnapshot): Unit = { - reporter.reportPeriodSnapshot(transformations.tail.foldLeft(transformations.head.apply(snapshot))((s, t) => t.apply(s))) + override def reportPeriodSnapshot(snapshot: PeriodSnapshot): Unit = { + reporter.reportPeriodSnapshot(transformations.tail.foldLeft(transformations.head.apply(snapshot))((s, t) => + t.apply(s) + )) + } } - } /** * Creates a transformation that only report metrics whose name matches the provided filter. @@ -68,4 +70,4 @@ object MetricReporter { ) } } -} \ No newline at end of file +} diff --git a/core/kamon-core/src/main/scala/kamon/module/Module.scala b/core/kamon-core/src/main/scala/kamon/module/Module.scala index 642713af1..103eef037 100644 --- a/core/kamon-core/src/main/scala/kamon/module/Module.scala +++ b/core/kamon-core/src/main/scala/kamon/module/Module.scala @@ -61,7 +61,7 @@ object ModuleFactory { /** * Initial settings that get passed into factories when creating an automatically detected module. */ - case class Settings ( + case class Settings( config: Config, executionContext: ExecutionContext ) @@ -73,7 +73,6 @@ object ModuleFactory { */ trait CombinedReporter extends MetricReporter with SpanReporter - object Module { sealed trait Kind @@ -113,7 +112,7 @@ object Module { * started in any call to Kamon.loadModules(). * @param factory FQCN of the ModuleFactory implementation for the module. */ - case class Settings ( + case class Settings( name: String, description: String, enabled: Boolean, @@ -121,4 +120,4 @@ object Module { metricsFilter: Option[Filter], collectInterval: Option[Duration] ) -} \ No newline at end of file +} diff --git a/core/kamon-core/src/main/scala/kamon/module/ModuleRegistry.scala b/core/kamon-core/src/main/scala/kamon/module/ModuleRegistry.scala index 41a100429..fc233c60e 100644 --- a/core/kamon-core/src/main/scala/kamon/module/ModuleRegistry.scala +++ b/core/kamon-core/src/main/scala/kamon/module/ModuleRegistry.scala @@ -18,7 +18,14 @@ package kamon package module import java.time.{Duration, Instant} -import java.util.concurrent.{CountDownLatch, Executors, ForkJoinPool, ScheduledExecutorService, ScheduledFuture, TimeUnit} +import java.util.concurrent.{ + CountDownLatch, + Executors, + ForkJoinPool, + ScheduledExecutorService, + ScheduledFuture, + TimeUnit +} import java.util.concurrent.atomic.AtomicReference import com.typesafe.config.Config import kamon.module.Module.Registration @@ -58,10 +65,10 @@ class ModuleRegistry(configuration: Configuration, clock: Clock, metricRegistry: } def shutdown(): Unit = synchronized { - if(_metricsTickerSchedule.get() != null) + if (_metricsTickerSchedule.get() != null) _metricsTickerSchedule.get().cancel(true) - if(_spansTickerSchedule.get() != null) + if (_spansTickerSchedule.get() != null) _spansTickerSchedule.get().cancel(true) _tickerExecutor.foreach(_.shutdown()) @@ -72,11 +79,21 @@ class ModuleRegistry(configuration: Configuration, clock: Clock, metricRegistry: register(name, description, reporter) } - def addReporter(name: String, description: Option[String], reporter: MetricReporter, metricFilter: Option[Filter]): Registration = { + def addReporter( + name: String, + description: Option[String], + reporter: MetricReporter, + metricFilter: Option[Filter] + ): Registration = { register(name, description, reporter, metricFilter, None) } - def addScheduledAction(name: String, description: Option[String], collector: ScheduledAction, interval: Duration): Registration = { + def addScheduledAction( + name: String, + description: Option[String], + collector: ScheduledAction, + interval: Duration + ): Registration = { register(name, description, collector, None, Some(interval)) } @@ -85,10 +102,15 @@ class ModuleRegistry(configuration: Configuration, clock: Clock, metricRegistry: * registration will fail. If the registered module is a MetricReporter and/or SpanReporter it will also be * registered to receive the metrics and/or spans data upon every tick. */ - def register(name: String, description: Option[String], module: Module, metricFilter: Option[Filter] = None, - interval: Option[Duration] = None): Registration = synchronized { + def register( + name: String, + description: Option[String], + module: Module, + metricFilter: Option[Filter] = None, + interval: Option[Duration] = None + ): Registration = synchronized { - if(_registeredModules.get(name).isEmpty) { + if (_registeredModules.get(name).isEmpty) { val inferredSettings = Module.Settings( name, description.getOrElse(module.getClass.getName), @@ -98,7 +120,8 @@ class ModuleRegistry(configuration: Configuration, clock: Clock, metricRegistry: interval ) - val moduleEntry = Entry(name, createExecutor(inferredSettings), true, inferredSettings, new AtomicReference(), module) + val moduleEntry = + Entry(name, createExecutor(inferredSettings), true, inferredSettings, new AtomicReference(), module) registerModule(moduleEntry) registration(moduleEntry) @@ -114,19 +137,21 @@ class ModuleRegistry(configuration: Configuration, clock: Clock, metricRegistry: */ def load(config: Config): Unit = synchronized { val configuredModules = readModuleSettings(config, true) - val automaticallyRegisteredModules = _registeredModules.filterNot { case (_, module) => module.programmaticallyAdded } + val automaticallyRegisteredModules = _registeredModules.filterNot { case (_, module) => + module.programmaticallyAdded + } // Start, reconfigure and stop modules that are still present but disabled. configuredModules.foreach { moduleSettings => automaticallyRegisteredModules.get(moduleSettings.name).fold { // The module does not exist in the registry, the only possible action is starting it, if enabled. - if(moduleSettings.enabled) { + if (moduleSettings.enabled) { createModule(moduleSettings, false).foreach(entry => registerModule(entry)) } } { existentModuleSettings => // When a module already exists it can either need to be stopped, or to be reconfigured. - if(moduleSettings.enabled) { + if (moduleSettings.enabled) { reconfigureModule(existentModuleSettings, config) } else { stopModule(existentModuleSettings) @@ -135,7 +160,8 @@ class ModuleRegistry(configuration: Configuration, clock: Clock, metricRegistry: } // Remove all modules that no longer exist in the configuration. - val missingModules = automaticallyRegisteredModules.filterKeys(moduleName => !configuredModules.exists(_.name == moduleName)) + val missingModules = + automaticallyRegisteredModules.filterKeys(moduleName => !configuredModules.exists(_.name == moduleName)) missingModules.foreach { case (_, entry) => stopModule(entry) } @@ -170,7 +196,6 @@ class ModuleRegistry(configuration: Configuration, clock: Clock, metricRegistry: Future.sequence(stoppedSignals).map(_ => ()) } - /** * (Re)Schedules the metrics ticker that periodically takes snapshots from the metric registry and sends them to * all available metric reporting modules. If a ticker was already scheduled then that scheduled job will be @@ -178,12 +203,12 @@ class ModuleRegistry(configuration: Configuration, clock: Clock, metricRegistry: */ private def scheduleMetricsTicker(scheduler: ScheduledExecutorService): Unit = { val currentMetricsTicker = _metricsTickerSchedule.get() - if(currentMetricsTicker != null) + if (currentMetricsTicker != null) currentMetricsTicker.cancel(false) _metricsTickerSchedule.set { val interval = _registrySettings.metricTickInterval.toMillis - val initialDelay = if(_registrySettings.optimisticMetricTickAlignment) { + val initialDelay = if (_registrySettings.optimisticMetricTickAlignment) { val now = clock.instant() val nextTick = Clock.nextAlignedInstant(now, _registrySettings.metricTickInterval) Duration.between(now, nextTick).toMillis @@ -192,15 +217,16 @@ class ModuleRegistry(configuration: Configuration, clock: Clock, metricRegistry: val ticker = new Runnable { var lastInstant = Instant.now(clock) - override def run(): Unit = try { - val currentInstant = Instant.now(clock) - val periodSnapshot = metricRegistry.snapshot(resetState = true) - - metricReporterModules().foreach(entry => scheduleMetricsTick(entry, periodSnapshot)) - lastInstant = currentInstant - } catch { - case NonFatal(t) => _logger.error("Failed to run a metrics tick", t) - } + override def run(): Unit = + try { + val currentInstant = Instant.now(clock) + val periodSnapshot = metricRegistry.snapshot(resetState = true) + + metricReporterModules().foreach(entry => scheduleMetricsTick(entry, periodSnapshot)) + lastInstant = currentInstant + } catch { + case NonFatal(t) => _logger.error("Failed to run a metrics tick", t) + } } scheduler.scheduleAtFixedRate(ticker, initialDelay, interval, TimeUnit.MILLISECONDS) @@ -214,20 +240,21 @@ class ModuleRegistry(configuration: Configuration, clock: Clock, metricRegistry: */ private def scheduleSpansTicker(scheduler: ScheduledExecutorService): Unit = { val currentSpansTicker = _spansTickerSchedule.get() - if(currentSpansTicker != null) + if (currentSpansTicker != null) currentSpansTicker.cancel(false) _spansTickerSchedule.set { val interval = _registrySettings.traceTickInterval.toMillis val ticker = new Runnable { - override def run(): Unit = try { - val spanBatch = tracer.spans() - spanReporterModules().foreach(entry => scheduleSpansBatch(entry, spanBatch)) + override def run(): Unit = + try { + val spanBatch = tracer.spans() + spanReporterModules().foreach(entry => scheduleSpansBatch(entry, spanBatch)) - } catch { - case NonFatal(t) => _logger.error("Failed to run a spans tick", t) - } + } catch { + case NonFatal(t) => _logger.error("Failed to run a spans tick", t) + } } scheduler.scheduleAtFixedRate(ticker, interval, interval, TimeUnit.MILLISECONDS) @@ -243,7 +270,7 @@ class ModuleRegistry(configuration: Configuration, clock: Clock, metricRegistry: private def scheduleAction(entry: Entry[ScheduledAction], scheduler: ScheduledExecutorService): Unit = { val intervalMills = entry.settings.collectInterval.get.toMillis - val scheduledFuture = scheduler.scheduleAtFixedRate( + val scheduledFuture = scheduler.scheduleAtFixedRate( collectorScheduleRunnable(entry), intervalMills, intervalMills, @@ -261,16 +288,19 @@ class ModuleRegistry(configuration: Configuration, clock: Clock, metricRegistry: .getOrElse(periodSnapshot) entry.module.reportPeriodSnapshot(filteredSnapshot) - } catch { case error: Throwable => - _logger.error(s"Reporter [${entry.name}] failed to process a metrics tick.", error) + } catch { + case error: Throwable => + _logger.error(s"Reporter [${entry.name}] failed to process a metrics tick.", error) } }(entry.executionContext) } private def scheduleSpansBatch(entry: Entry[SpanReporter], spanBatch: Seq[Span.Finished]): Unit = { Future { - try entry.module.reportSpans(spanBatch) catch { case error: Throwable => - _logger.error(s"Reporter [${entry.name}] failed to process a spans tick.", error) + try entry.module.reportSpans(spanBatch) + catch { + case error: Throwable => + _logger.error(s"Reporter [${entry.name}] failed to process a spans tick.", error) } }(entry.executionContext) } @@ -295,11 +325,11 @@ class ModuleRegistry(configuration: Configuration, clock: Clock, metricRegistry: private def stopReporterTickers(): Unit = { val currentMetricsTicker = _metricsTickerSchedule.get() - if(currentMetricsTicker != null) + if (currentMetricsTicker != null) currentMetricsTicker.cancel(false) val currentSpansTicker = _spansTickerSchedule.get() - if(currentSpansTicker != null) + if (currentSpansTicker != null) currentSpansTicker.cancel(false) } @@ -330,7 +360,7 @@ class ModuleRegistry(configuration: Configuration, clock: Clock, metricRegistry: ) } - if(emitConfigurationWarnings) { + if (emitConfigurationWarnings) { moduleSettings.failed.foreach { t => _logger.warn(s"Failed to read configuration for module [$modulePath]", t) @@ -340,14 +370,16 @@ class ModuleRegistry(configuration: Configuration, clock: Clock, metricRegistry: moduleConfig.hasPath("extension-class") if (hasLegacySettings) { - _logger.warn(s"Module [$modulePath] contains legacy configuration settings, please ensure that no legacy configuration") + _logger.warn( + s"Module [$modulePath] contains legacy configuration settings, please ensure that no legacy configuration" + ) } } } moduleSettings - } filter(_.isSuccess) map(_.get) toSeq + } filter (_.isSuccess) map (_.get) toSeq } /** @@ -386,11 +418,11 @@ class ModuleRegistry(configuration: Configuration, clock: Clock, metricRegistry: val isMetricReporter = classOf[MetricReporter].isAssignableFrom(clazz) val isSpanReporter = classOf[SpanReporter].isAssignableFrom(clazz) - if(isSpanReporter && isMetricReporter) + if (isSpanReporter && isMetricReporter) Module.Kind.CombinedReporter - else if(isMetricReporter) + else if (isMetricReporter) Module.Kind.MetricsReporter - else if(isSpanReporter) + else if (isSpanReporter) Module.Kind.SpansReporter else Module.Kind.ScheduledAction @@ -413,7 +445,8 @@ class ModuleRegistry(configuration: Configuration, clock: Clock, metricRegistry: moduleKind, programmaticallyRegistered = false, moduleSettings.enabled, - isActive) + isActive + ) }) val programmaticallyAddedModules = _registeredModules @@ -435,13 +468,13 @@ class ModuleRegistry(configuration: Configuration, clock: Clock, metricRegistry: private def registerModule(entry: Entry[Module]): Unit = { _registeredModules = _registeredModules + (entry.name -> entry) - if(entry.module.isInstanceOf[MetricReporter]) + if (entry.module.isInstanceOf[MetricReporter]) _metricReporterModules = _metricReporterModules + (entry.name -> entry.asInstanceOf[Entry[MetricReporter]]) - if(entry.module.isInstanceOf[SpanReporter]) + if (entry.module.isInstanceOf[SpanReporter]) _spanReporterModules = _spanReporterModules + (entry.name -> entry.asInstanceOf[Entry[SpanReporter]]) - if(entry.module.isInstanceOf[ScheduledAction] && _tickerExecutor.nonEmpty) + if (entry.module.isInstanceOf[ScheduledAction] && _tickerExecutor.nonEmpty) scheduleAction(entry.asInstanceOf[Entry[ScheduledAction]], _tickerExecutor.get) } @@ -451,7 +484,7 @@ class ModuleRegistry(configuration: Configuration, clock: Clock, metricRegistry: * context. The returned future completes when the module finishes its stop procedure. */ private def stopModule(entry: Entry[Module]): Future[Unit] = synchronized { - if(_registeredModules.get(entry.name).nonEmpty) { + if (_registeredModules.get(entry.name).nonEmpty) { // Remove the module from all registries _registeredModules = _registeredModules - entry.name @@ -465,7 +498,6 @@ class ModuleRegistry(configuration: Configuration, clock: Clock, metricRegistry: scheduleSpansBatch(entry.asInstanceOf[Entry[SpanReporter]], tracer.spans()) } - // Schedule a call to stop on the module val stopPromise = Promise[Unit]() entry.executionContext.execute(new Runnable { @@ -528,4 +560,3 @@ class ModuleRegistry(configuration: Configuration, clock: Clock, metricRegistry: module: T ) } - diff --git a/core/kamon-core/src/main/scala/kamon/module/ScheduledAction.scala b/core/kamon-core/src/main/scala/kamon/module/ScheduledAction.scala index 0218c3e30..bcecd63ab 100644 --- a/core/kamon-core/src/main/scala/kamon/module/ScheduledAction.scala +++ b/core/kamon-core/src/main/scala/kamon/module/ScheduledAction.scala @@ -16,7 +16,6 @@ package kamon.module - /** * Modules implementing this will have a receive a scheduled call to their `run` method in a fixed interval. The * call interval is controlled by the `kamon.modules.{module-name}.interval` setting, or passed in programmatically diff --git a/core/kamon-core/src/main/scala/kamon/package.scala b/core/kamon-core/src/main/scala/kamon/package.scala index 80f099566..4f6917acc 100644 --- a/core/kamon-core/src/main/scala/kamon/package.scala +++ b/core/kamon-core/src/main/scala/kamon/package.scala @@ -62,7 +62,6 @@ package object kamon { } } - /** * Atomic variant of [scala.collection.concurrent.TrieMap#getOrElseUpdate()] method with cleanup and init functions. */ diff --git a/core/kamon-core/src/main/scala/kamon/status/Environment.scala b/core/kamon-core/src/main/scala/kamon/status/Environment.scala index 4292bcd8a..e9634dd3a 100644 --- a/core/kamon-core/src/main/scala/kamon/status/Environment.scala +++ b/core/kamon-core/src/main/scala/kamon/status/Environment.scala @@ -89,12 +89,14 @@ object Environment { } private def generateHostname(): String = { - try InetAddress.getLocalHost.getHostName() catch { case t: Throwable => - _logger.warn("Could not automatically resolve a host name for this instance, falling back to 'localhost'", t) - "localhost" + try InetAddress.getLocalHost.getHostName() + catch { + case t: Throwable => + _logger.warn("Could not automatically resolve a host name for this instance, falling back to 'localhost'", t) + "localhost" } } private def readValueOrGenerate(configuredValue: String, generator: => String): String = - if(configuredValue == "auto") generator else configuredValue + if (configuredValue == "auto") generator else configuredValue } diff --git a/core/kamon-core/src/main/scala/kamon/status/InstrumentationStatus.scala b/core/kamon-core/src/main/scala/kamon/status/InstrumentationStatus.scala index b9f586f50..6e10aa9b4 100644 --- a/core/kamon-core/src/main/scala/kamon/status/InstrumentationStatus.scala +++ b/core/kamon-core/src/main/scala/kamon/status/InstrumentationStatus.scala @@ -37,7 +37,6 @@ object InstrumentationStatus { private val _kanelaLoadedPropertyName = "kanela.loaded" private val _registryClassName = "kanela.agent.api.instrumentation.listener.InstrumentationRegistryListener" - /** * Tries to fetch the current instrumentation information from Kanela and assemble a status instance. Since the * status information will be present on the System ClassLoader only after the Kanela agent has been activated (it @@ -74,11 +73,12 @@ object InstrumentationStatus { Status.Instrumentation(present, Option(kanelaVersion), modules.toSeq, errors) } catch { case t: Throwable => - - if(warnIfFailed) { + if (warnIfFailed) { t match { case _: ClassNotFoundException if warnIfFailed => - _logger.warn("Failed to load the instrumentation modules status because the Kanela agent is not available") + _logger.warn( + "Failed to load the instrumentation modules status because the Kanela agent is not available" + ) case t: Throwable if warnIfFailed => _logger.warn("Failed to load the instrumentation modules status", t) @@ -93,7 +93,7 @@ object InstrumentationStatus { * Transforms a Map-encoded module into a typed instance. The property names are tied to Kanela's implementation */ private def toModule(map: JavaMap[String, String]): Status.Instrumentation.ModuleInfo = { - Status.Instrumentation.ModuleInfo ( + Status.Instrumentation.ModuleInfo( map.get("path"), map.get("name"), map.get("description"), diff --git a/core/kamon-core/src/main/scala/kamon/status/Status.scala b/core/kamon-core/src/main/scala/kamon/status/Status.scala index 96729ed38..b6f031235 100644 --- a/core/kamon-core/src/main/scala/kamon/status/Status.scala +++ b/core/kamon-core/src/main/scala/kamon/status/Status.scala @@ -23,7 +23,6 @@ import kamon.module.ModuleRegistry import kamon.module.Module.{Kind => ModuleKind} import kamon.tag.TagSet - /** * Exposes Kamon components' status information. This is meant to be used for informational and debugging purposes and * by no means should replace the use of reporters to extract information from Kamon. @@ -59,7 +58,6 @@ class Status(_moduleRegistry: ModuleRegistry, _metricRegistry: MetricRegistry, c } - object Status { /** Describes the global settings currently being used by Kamon */ @@ -94,7 +92,7 @@ object Status { * Describes a metric from a metric registry. Contains the basic metric information and details on all instruments * registered for that metric. */ - case class Metric ( + case class Metric( name: String, description: String, unit: MeasurementUnit, @@ -103,7 +101,7 @@ object Status { ) /** Describes the combination of tags in any given instrument */ - case class Instrument ( + case class Instrument( tags: TagSet ) @@ -111,7 +109,7 @@ object Status { * Describes all known instrumentation modules. This data is completely untyped and not expected to be used anywhere * outside Kamon. The data is injected on runtime by the Kanela instrumentation agent. */ - case class Instrumentation ( + case class Instrumentation( present: Boolean, kanelaVersion: Option[String], modules: Seq[Status.Instrumentation.ModuleInfo], @@ -126,7 +124,7 @@ object Status { * but some modules might be shipped in a disabled state or forced to be disabled via configuration. The "active" * flag tells whether the modules has already applied instrumentation to any of its target types. */ - case class ModuleInfo ( + case class ModuleInfo( path: String, name: String, description: String, @@ -137,7 +135,7 @@ object Status { /** * Describes errors that might have occurred while transforming a target type. */ - case class TypeError ( + case class TypeError( targetType: String, errors: Seq[Throwable] ) diff --git a/core/kamon-core/src/main/scala/kamon/tag/Lookups.scala b/core/kamon-core/src/main/scala/kamon/tag/Lookups.scala index 0e7fdabc9..91d5759e1 100644 --- a/core/kamon-core/src/main/scala/kamon/tag/Lookups.scala +++ b/core/kamon-core/src/main/scala/kamon/tag/Lookups.scala @@ -20,7 +20,6 @@ package tag import java.util.Optional import kamon.tag.TagSet.Lookup - object Lookups { /** @@ -68,7 +67,7 @@ object Lookups { def coerce(key: String): Lookup[String] = new Lookup[String] { override def execute(storage: TagSet.Storage): String = { val value = storage.get(key) - if(value == null) + if (value == null) "unknown" else value.toString @@ -85,7 +84,7 @@ object Lookups { def coerce(key: String, default: String): Lookup[String] = new Lookup[String] { override def execute(storage: TagSet.Storage): String = { val value = storage.get(key) - if(value == null) + if (value == null) default else value.toString @@ -146,18 +145,23 @@ object Lookups { findAndTransform(key, storage, _longOptional, Optional.empty(), _longSafetyCheck) } - //////////////////////////////////////////////////////////////// // Transformation helpers for the lookup DSL // //////////////////////////////////////////////////////////////// @inline - private def findAndTransform[T, R](key: String, storage: TagSet.Storage, transform: R => T, default: T, safetyCheck: Any => Boolean): T = { + private def findAndTransform[T, R]( + key: String, + storage: TagSet.Storage, + transform: R => T, + default: T, + safetyCheck: Any => Boolean + ): T = { // This assumes that this code will only be used to lookup values from a Tags instance // for which the underlying map always has "null" as the default value. val value = storage.get(key) - if(safetyCheck(value)) + if (safetyCheck(value)) transform(value.asInstanceOf[R]) else default diff --git a/core/kamon-core/src/main/scala/kamon/tag/Tag.scala b/core/kamon-core/src/main/scala/kamon/tag/Tag.scala index ddbedd834..b95d217d6 100644 --- a/core/kamon-core/src/main/scala/kamon/tag/Tag.scala +++ b/core/kamon-core/src/main/scala/kamon/tag/Tag.scala @@ -41,7 +41,6 @@ object Tag { def value: JString } - /** * Represents a String key pointing to a Boolean value. */ @@ -49,7 +48,6 @@ object Tag { def value: JBoolean } - /** * Represents a String key pointing to a Long value. */ @@ -57,7 +55,6 @@ object Tag { def value: JLong } - /** * Returns the value held inside of a Tag instance. This utility function is specially useful when iterating over * tags but not caring about the concrete tag type. @@ -68,4 +65,3 @@ object Tag { case t: Tag.Long => t.value } } - diff --git a/core/kamon-core/src/main/scala/kamon/tag/TagSet.scala b/core/kamon-core/src/main/scala/kamon/tag/TagSet.scala index 54b097413..68c185c25 100644 --- a/core/kamon-core/src/main/scala/kamon/tag/TagSet.scala +++ b/core/kamon-core/src/main/scala/kamon/tag/TagSet.scala @@ -50,7 +50,7 @@ import org.slf4j.LoggerFactory * cumbersome operation is rarely necessary on user-facing code. * */ -class TagSet private(private val _underlying: UnifiedMap[String, Any]) { +class TagSet private (private val _underlying: UnifiedMap[String, Any]) { import TagSet.withPair /** @@ -90,11 +90,11 @@ class TagSet private(private val _underlying: UnifiedMap[String, Any]) { * Creates a new TagSet instance without the provided key, if it was present. */ def without(key: String): TagSet = { - if(_underlying.containsKey(key)) { + if (_underlying.containsKey(key)) { val withoutKey = new UnifiedMap[String, Any](_underlying.size()) _underlying.forEachKeyValue(new BiConsumer[String, Any] { override def accept(t: String, u: Any): Unit = - if(t != key) withoutKey.put(t, u) + if (t != key) withoutKey.put(t, u) }) new TagSet(withoutKey) @@ -193,19 +193,19 @@ class TagSet private(private val _underlying: UnifiedMap[String, Any]) { } private def stringTag(key: String, value: String): Tag.String = - if(_stringTag == null) { + if (_stringTag == null) { _stringTag = new TagSet.mutable.String(key, value) _stringTag } else _stringTag.updated(key, value) private def booleanTag(key: String, value: Boolean): Tag.Boolean = - if(_booleanTag == null) { + if (_booleanTag == null) { _booleanTag = new TagSet.mutable.Boolean(key, value) _booleanTag } else _booleanTag.updated(key, value) private def longTag(key: String, value: Long): Tag.Long = - if(_longTag == null) { + if (_longTag == null) { _longTag = new TagSet.mutable.Long(key, value) _longTag } else _longTag.updated(key, value) @@ -223,9 +223,9 @@ class TagSet private(private val _underlying: UnifiedMap[String, Any]) { var hasTags = false val iterator = _underlying.entrySet().iterator() - while(iterator.hasNext) { + while (iterator.hasNext) { val pair = iterator.next() - if(hasTags) + if (hasTags) sb.append(",") sb.append(pair.getKey) @@ -265,7 +265,6 @@ object TagSet { def execute(storage: TagSet.Storage): T } - /** * A temporary structure that accumulates key/value and creates a new TagSet instance from them. It is faster to use * a Builder and add tags to it rather than creating TagSet and add each key individually. Builder instances rely on @@ -289,7 +288,6 @@ object TagSet { def build(): TagSet } - /** * Abstracts the actual storage used for a TagSet. This interface resembles a stripped down interface of an immutable * map of String to Any, used to expose the underlying structure where tags are stored to Lookups, without leaking @@ -316,53 +314,46 @@ object TagSet { } - /** * A valid instance of tags that doesn't contain any pairs. */ val Empty = new TagSet(UnifiedMap.newMap[String, Any]()) - /** * Creates a new Builder instance. */ def builder(): Builder = new Builder.ChainedArray - /** * Construct a new TagSet instance with a single key/value pair. */ def of(key: String, value: java.lang.String): TagSet = withPair(Empty, key, value) - /** * Construct a new TagSet instance with a single key/value pair. */ def of(key: String, value: java.lang.Boolean): TagSet = withPair(Empty, key, value) - /** * Construct a new TagSet instance with a single key/value pair. */ def of(key: String, value: java.lang.Long): TagSet = withPair(Empty, key, value) - /** * Constructs a new TagSet instance from a Map. The returned TagSet will only contain the entries that have String, * Long or Boolean values from the supplied map, any other entry in the map will be ignored. */ def from(map: Map[String, Any]): TagSet = { val unifiedMap = new UnifiedMap[String, Any](map.size) - map.foreach { pair => if(isValidPair(pair._1, pair._2, checkValueType = true)) unifiedMap.put(pair._1, pair._2)} + map.foreach { pair => if (isValidPair(pair._1, pair._2, checkValueType = true)) unifiedMap.put(pair._1, pair._2) } new TagSet(unifiedMap) } - /** * Constructs a new TagSet instance from a Map. The returned TagSet will only contain the entries that have String, * Long or Boolean values from the supplied map, any other entry in the map will be ignored. @@ -371,17 +362,16 @@ object TagSet { val unifiedMap = new UnifiedMap[String, Any](map.size) map.forEach(new BiConsumer[String, Any] { override def accept(key: String, value: Any): Unit = - if(isValidPair(key, value, checkValueType = true)) unifiedMap.put(key, value) + if (isValidPair(key, value, checkValueType = true)) unifiedMap.put(key, value) }) new TagSet(unifiedMap) } - private val _logger = LoggerFactory.getLogger(classOf[TagSet]) private def withPair(parent: TagSet, key: String, value: Any): TagSet = - if(isValidPair(key, value, checkValueType = true)) { + if (isValidPair(key, value, checkValueType = true)) { val mergedMap = new UnifiedMap[String, Any](parent._underlying.size() + 1) mergedMap.putAll(parent._underlying) mergedMap.put(key, value) @@ -394,10 +384,10 @@ object TagSet { val isValidValue = value != null && (!checkValueType || isAllowedTagValue(value)) val isValid = isValidKey && isValidValue - if(!isValid && _logger.isDebugEnabled) { - if(!isValidKey && !isValidValue) + if (!isValid && _logger.isDebugEnabled) { + if (!isValidKey && !isValidValue) _logger.debug(s"Dismissing tag with invalid key [$key] and invalid value [$value]") - else if(!isValidKey) + else if (!isValidKey) _logger.debug(s"Dismissing tag with invalid key [$key] and value [$value]") else _logger.debug(s"Dismissing tag with key [$key] and invalid value [$value]") @@ -469,7 +459,7 @@ object TagSet { } override def add(tags: TagSet): Builder = { - if(tags.nonEmpty()) + if (tags.nonEmpty()) tags.iterator().foreach(t => addPair(t.key, Tag.unwrapValue(t))) this @@ -482,13 +472,13 @@ object TagSet { var currentKey = currentBlock(position) var currentValue = currentBlock(position + 1) - while(currentKey != null) { + while (currentKey != null) { unifiedMap.put(currentKey.asInstanceOf[String], currentValue) position += 2 - if(position == ChainedArray.BlockSize) { + if (position == ChainedArray.BlockSize) { val nextBlock = currentBlock(currentBlock.length - 1) - if(nextBlock == null) { + if (nextBlock == null) { currentKey = null currentValue = null } else { @@ -507,7 +497,7 @@ object TagSet { } private def addPair(key: String, value: Any): Unit = { - if(isValidPair(key, value, checkValueType = false)) { + if (isValidPair(key, value, checkValueType = false)) { if (_position == ChainedArray.BlockSize) { // Adds an extra block at the end of the current one. val extraBlock = newBlock() @@ -531,4 +521,4 @@ object TagSet { val BlockSize = EntriesPerBlock * 2 } } -} \ No newline at end of file +} diff --git a/core/kamon-core/src/main/scala/kamon/trace/AdaptiveSampler.scala b/core/kamon-core/src/main/scala/kamon/trace/AdaptiveSampler.scala index feb7e35a7..97eae1caa 100644 --- a/core/kamon-core/src/main/scala/kamon/trace/AdaptiveSampler.scala +++ b/core/kamon-core/src/main/scala/kamon/trace/AdaptiveSampler.scala @@ -45,19 +45,20 @@ class AdaptiveSampler extends Sampler { private val _affirmativeDecisionCounter = Sampler.Metrics.samplingDecisions("adaptive", SamplingDecision.Sample) private val _negativeDecisionCounter = Sampler.Metrics.samplingDecisions("adaptive", SamplingDecision.DoNotSample) - override def decide(operation: Sampler.Operation): SamplingDecision = { val operationName = operation.operationName() - val operationSampler = _samplers.getOrElse(operationName, { - // It might happen that the first time we see an operation under high concurrent throughput we will reach this - // block more than once, but worse case effect is that we will rebalance the operation samplers more than once. - val sampler = _samplers.getOrElseUpdate(operationName, buildOperationSampler(operationName)) - rebalance() - sampler - }) + val operationSampler = _samplers.getOrElse( + operationName, { + // It might happen that the first time we see an operation under high concurrent throughput we will reach this + // block more than once, but worse case effect is that we will rebalance the operation samplers more than once. + val sampler = _samplers.getOrElseUpdate(operationName, buildOperationSampler(operationName)) + rebalance() + sampler + } + ) val decision = operationSampler.decide() - if(decision == SamplingDecision.Sample) + if (decision == SamplingDecision.Sample) _affirmativeDecisionCounter.increment() else _negativeDecisionCounter.increment() @@ -89,36 +90,37 @@ class AdaptiveSampler extends Sampler { val throughputGoal = _settings.throughput val basePerOperationThroughput = throughputGoal / dynamicallySampledOperations.size.toDouble - var allocationDelta = 0D + var allocationDelta = 0d var allocationsWithCustomThroughput = 0L - val allocations = dynamicallySampledOperations.map { operationSampler => { - import operationSampler.rules - - // On the first round we only assign throughput values to operations that require modifications to their default - // allocation in order to meet their rules. - var hasCustomThroughput = false - var operationThroughput = basePerOperationThroughput - val minimumCap = rules.minimumThroughput.getOrElse(0D) - val maximumCap = rules.maximumThroughput.getOrElse(throughputGoal) - - if(operationThroughput < minimumCap) { - operationThroughput = minimumCap - hasCustomThroughput = true - } - - if(operationThroughput > maximumCap) { - operationThroughput = maximumCap - hasCustomThroughput = true - } - - if(hasCustomThroughput) { - allocationDelta += basePerOperationThroughput - operationThroughput - allocationsWithCustomThroughput += 1 + val allocations = dynamicallySampledOperations.map { operationSampler => + { + import operationSampler.rules + + // On the first round we only assign throughput values to operations that require modifications to their default + // allocation in order to meet their rules. + var hasCustomThroughput = false + var operationThroughput = basePerOperationThroughput + val minimumCap = rules.minimumThroughput.getOrElse(0d) + val maximumCap = rules.maximumThroughput.getOrElse(throughputGoal) + + if (operationThroughput < minimumCap) { + operationThroughput = minimumCap + hasCustomThroughput = true + } + + if (operationThroughput > maximumCap) { + operationThroughput = maximumCap + hasCustomThroughput = true + } + + if (hasCustomThroughput) { + allocationDelta += basePerOperationThroughput - operationThroughput + allocationsWithCustomThroughput += 1 + } + + Allocation(operationThroughput, hasCustomThroughput, operationSampler) } - - Allocation(operationThroughput, hasCustomThroughput, operationSampler) - }} - + } // Step 2: Adjust the per-operation throughput allocation for all operations that do not have any custom throughput // based on configured rules. This section compensates for any deficit or surplus that might arise from @@ -126,12 +128,12 @@ class AdaptiveSampler extends Sampler { // dynamically adjusted without affecting compliance with their rules. // val correctedAllocations = - if(allocationsWithCustomThroughput == 0) allocations else { + if (allocationsWithCustomThroughput == 0) allocations + else { val perOperationDelta = allocationDelta / (allocations.size - allocationsWithCustomThroughput).toDouble allocations.map(a => if (a.hasFixedThroughput) a else a.copy(throughput = a.throughput + perOperationDelta)) } - // Step 3: Apply the base throughput allocations to all operations samplers. // correctedAllocations.foreach(a => a.operationSampler.updateThroughput(a.throughput)) @@ -149,49 +151,49 @@ class AdaptiveSampler extends Sampler { .map(s => (s, s.throughputAverage())) .sortBy { case (sampler, throughputAverage) => Math.min(sampler.throughputCap(), throughputAverage) } - // Step 1: Go through all operations and try to find chunks of unused throughput that will be later distributed // across operations that could make us of that throughput, if any. // - var totalUnusedThroughput = 0D + var totalUnusedThroughput = 0d randomSamplersWithStats.foreach { p => totalUnusedThroughput += calculateUnusedThroughput(p) } - // Step 2: Figure out which operations can make use of additional throughput and boost them accordingly. Since the // samplers are ordered by throughput any unused shares will be accumulated, giving bigger shares to the // operations with more throughput. // var boostedOperationCount = 0 - randomSamplersWithStats.foreach { case (sampler, throughputAverage) => { - val canBoost = - sampler.probability() > 0D && // Skips boosting on the first round of each sampler - totalUnusedThroughput > 0D // Only boost if there is actually some leftover to boost - - val boost = if(canBoost) { - val boostShare = totalUnusedThroughput / (operationCount - boostedOperationCount).toDouble - val proposedThroughput = sampler.throughput() + boostShare - - // Figure out how much we can boost this operation without breaking the expected maximum throughput, and taking - // into account that even though an operation could reach higher throughput from the limits perspective, its - // historical throughput is what really tells us what throughput we can expect. - val maximumAllowedThroughput = Math.min(proposedThroughput, sampler.throughputCap()) - val maximumPossibleThroughput = Math.min(maximumAllowedThroughput, throughputAverage) - val usableBoost = maximumPossibleThroughput - sampler.throughput() - boostedOperationCount += 1 - - if(usableBoost >= boostShare) { - totalUnusedThroughput -= boostShare - boostShare - } else if(usableBoost > 0D) { - totalUnusedThroughput -= usableBoost - boostShare - } else 0D - - } else 0D - - val probability = (sampler.throughput() + boost) / throughputAverage - sampler.updateProbability(probability) - }} + randomSamplersWithStats.foreach { + case (sampler, throughputAverage) => { + val canBoost = + sampler.probability() > 0d && // Skips boosting on the first round of each sampler + totalUnusedThroughput > 0d // Only boost if there is actually some leftover to boost + + val boost = if (canBoost) { + val boostShare = totalUnusedThroughput / (operationCount - boostedOperationCount).toDouble + val proposedThroughput = sampler.throughput() + boostShare + + // Figure out how much we can boost this operation without breaking the expected maximum throughput, and taking + // into account that even though an operation could reach higher throughput from the limits perspective, its + // historical throughput is what really tells us what throughput we can expect. + val maximumAllowedThroughput = Math.min(proposedThroughput, sampler.throughputCap()) + val maximumPossibleThroughput = Math.min(maximumAllowedThroughput, throughputAverage) + val usableBoost = maximumPossibleThroughput - sampler.throughput() + boostedOperationCount += 1 + + if (usableBoost >= boostShare) { + totalUnusedThroughput -= boostShare + boostShare + } else if (usableBoost > 0d) { + totalUnusedThroughput -= usableBoost + boostShare + } else 0d + + } else 0d + + val probability = (sampler.throughput() + boost) / throughputAverage + sampler.updateProbability(probability) + } + } } def reconfigure(newConfig: Config): Unit = { @@ -205,7 +207,7 @@ class AdaptiveSampler extends Sampler { private def calculateUnusedThroughput(pair: (OperationSampler.Random, Double)): Double = { val (sampler, throughputAverage) = pair val throughputDelta = sampler.throughput() - throughputAverage - if (throughputDelta > 0D) throughputDelta else 0D + if (throughputDelta > 0d) throughputDelta else 0d } } @@ -228,7 +230,7 @@ object AdaptiveSampler { * Settings for an adaptive sampler instance. Take a look at the "kamon.trace.adaptive-sampler" section on the * configuration file for more details. */ - case class Settings ( + case class Settings( throughput: Double, groups: Seq[Settings.Group] ) @@ -242,7 +244,7 @@ object AdaptiveSampler { * @param operations Names of all operations that will be part of the group. * @param rules Rules to should be applied to all operations in this group. */ - case class Group ( + case class Group( name: String, operations: Seq[String], rules: Rules @@ -255,7 +257,7 @@ object AdaptiveSampler { * @param minimumThroughput Minimum throughput that the sampler will try to guarantee for a matched operation. * @param maximumThroughput Maximum throughput that the sampler will try to guarantee for a matched operation. */ - case class Rules ( + case class Rules( sample: Option[SamplingDecision], minimumThroughput: Option[Double], maximumThroughput: Option[Double] @@ -299,7 +301,7 @@ object AdaptiveSampler { } /** Encapsulates throughput allocation information for the rebalancing phase of the adaptive sampler */ - private case class Allocation ( + private case class Allocation( throughput: Double, hasFixedThroughput: Boolean, operationSampler: OperationSampler.Random @@ -329,8 +331,8 @@ object AdaptiveSampler { class Random(operationName: String, val rules: Settings.Rules) extends OperationSampler { @volatile private var _lowerBoundary = 0L @volatile private var _upperBoundary = 0L - @volatile private var _throughput = 0D - @volatile private var _probability = 0D + @volatile private var _throughput = 0d + @volatile private var _probability = 0d private val _decisions = new LongAdder() private val _throughputAverage = EWMA.create() @@ -362,11 +364,11 @@ object AdaptiveSampler { */ private def decisionHistory(): Long = { val decisions = _decisions.sumAndReset() - _decisionsPerTickPos = if(_decisionsPerTickPos == (_decisionsHistorySize - 1)) 0 else _decisionsPerTickPos + 1 + _decisionsPerTickPos = if (_decisionsPerTickPos == (_decisionsHistorySize - 1)) 0 else _decisionsPerTickPos + 1 _decisionsPerTick.update(_decisionsPerTickPos, decisions) _tickCount += 1 - if(_tickCount < _decisionsHistorySize) { + if (_tickCount < _decisionsHistorySize) { val currentSum = _decisionsPerTick.sum val currentAverage = Math.floorDiv(currentSum, _tickCount) currentSum + (currentAverage * _decisionsHistorySize - _tickCount) @@ -374,7 +376,7 @@ object AdaptiveSampler { } else _decisionsPerTick.sum } - def throughput(): Double = + def throughput(): Double = _throughput def throughputCap(): Double = @@ -387,7 +389,7 @@ object AdaptiveSampler { _throughput = throughput def updateProbability(probability: Double): Unit = synchronized { - val actualProbability = if(probability > 1D) 1D else if (probability < 0D) 0D else probability + val actualProbability = if (probability > 1d) 1d else if (probability < 0d) 0d else probability _probability = actualProbability _upperBoundary = (Long.MaxValue * actualProbability).toLong _lowerBoundary = -_upperBoundary @@ -397,4 +399,4 @@ object AdaptiveSampler { s"Constant{operation=$operationName, probability=${_probability}" } } -} \ No newline at end of file +} diff --git a/core/kamon-core/src/main/scala/kamon/trace/ConstantSampler.scala b/core/kamon-core/src/main/scala/kamon/trace/ConstantSampler.scala index e6e834d86..9e7f9f5ee 100644 --- a/core/kamon-core/src/main/scala/kamon/trace/ConstantSampler.scala +++ b/core/kamon-core/src/main/scala/kamon/trace/ConstantSampler.scala @@ -22,7 +22,7 @@ import kamon.trace.Trace.SamplingDecision /** * Sampler that always returns the same sampling decision. */ -class ConstantSampler private(decision: SamplingDecision) extends Sampler { +class ConstantSampler private (decision: SamplingDecision) extends Sampler { private val _decisionCounter = Sampler.Metrics.samplingDecisions("constant", decision) override def decide(operation: Sampler.Operation): SamplingDecision = { @@ -41,4 +41,4 @@ object ConstantSampler { /** Sampler the never samples requests */ val Never = new ConstantSampler(SamplingDecision.DoNotSample) -} \ No newline at end of file +} diff --git a/core/kamon-core/src/main/scala/kamon/trace/Hooks.scala b/core/kamon-core/src/main/scala/kamon/trace/Hooks.scala index f96170c80..4dccd1728 100644 --- a/core/kamon-core/src/main/scala/kamon/trace/Hooks.scala +++ b/core/kamon-core/src/main/scala/kamon/trace/Hooks.scala @@ -34,11 +34,9 @@ object Hooks { override def beforeStart(builder: SpanBuilder): Unit = builder.name(operationName) } - /** Context key on used to store and retrieve PreStartTransformation instances on/from the current Context. */ val Key = Context.key[Tracer.PreStartHook]("preStartTransformation", Noop) - /** * Tries to find a PreStartHook instance on the current Context and apply it. Since the default value for the * Context key is the Noop implementation, no changes will be applied if no PreStartHook is found on the current @@ -49,7 +47,6 @@ object Hooks { Kamon.currentContext().get(PreStart.Key).beforeStart(builder) } - /** PreStartTransformation implementation which does not apply any changes to the provided SpanBuilder. */ object Noop extends Tracer.PreStartHook { override def beforeStart(builder: SpanBuilder): Unit = {} @@ -57,9 +54,6 @@ object Hooks { } - - - object PreFinish { /** @@ -70,11 +64,9 @@ object Hooks { override def beforeFinish(span: Span): Unit = span.name(operationName) } - /** Context key on used to store and retrieve PreFinishTransformation instances on/from the current Context. */ val Key = Context.key[Tracer.PreFinishHook]("preFinishTransformation", Noop) - /** * Tries to find a PreFinishHook instance on the current Context and apply it. Since the default value for the * Context key is the Noop implementation, no changes will be applied if no PreFinishHook is found on the current diff --git a/core/kamon-core/src/main/scala/kamon/trace/Identifier.scala b/core/kamon-core/src/main/scala/kamon/trace/Identifier.scala index e9632220d..fbd0b3217 100644 --- a/core/kamon-core/src/main/scala/kamon/trace/Identifier.scala +++ b/core/kamon-core/src/main/scala/kamon/trace/Identifier.scala @@ -24,7 +24,6 @@ import kamon.util.HexCodec import scala.util.Try - /** * Encapsulates an identifier in its String and Byte representations. Since it is a very common practice to include * Trace and (sometimes) Span identifiers on logs we make heavy use of the String representation since Identifiers @@ -42,7 +41,7 @@ case class Identifier(string: String, bytes: Array[Byte]) { string.isEmpty override def equals(obj: Any): Boolean = { - if(obj != null && obj.isInstanceOf[Identifier]) + if (obj != null && obj.isInstanceOf[Identifier]) obj.asInstanceOf[Identifier].string == string else false } @@ -59,7 +58,7 @@ object Identifier { * @param traceIdFactory Factory to be used for the Trace identifiers * @param spanIdFactory Factory to be used for the Span identifiers */ - case class Scheme ( + case class Scheme( traceIdFactory: Factory, spanIdFactory: Factory ) @@ -78,7 +77,6 @@ object Identifier { } - /** * Generates random identifiers and parses identifiers from both string and binary representations. */ @@ -100,7 +98,6 @@ object Identifier { def from(bytes: Array[Byte]): Identifier } - object Factory { /** @@ -117,20 +114,20 @@ object Identifier { Identifier(HexCodec.toLowerHex(random), data.array()) } - override def from(string: String): Identifier = Try { + override def from(string: String): Identifier = Try { val identifierLong = HexCodec.lowerHexToUnsignedLong(string) val data = ByteBuffer.allocate(8) data.putLong(identifierLong) Identifier(string, data.array()) - } getOrElse(Empty) + } getOrElse (Empty) override def from(bytes: Array[Byte]): Identifier = Try { val buffer = ByteBuffer.wrap(bytes) val identifierLong = buffer.getLong Identifier(HexCodec.toLowerHex(identifierLong), bytes) - } getOrElse(Empty) + } getOrElse (Empty) } /** @@ -148,7 +145,7 @@ object Identifier { Identifier(HexCodec.toLowerHex(highLong) + HexCodec.toLowerHex(lowLong), data.array()) } - override def from(string: String): Identifier = Try { + override def from(string: String): Identifier = Try { val highPart = HexCodec.lowerHexToUnsignedLong(string.substring(0, 16)) val lowPart = HexCodec.lowerHexToUnsignedLong(string.substring(16, 32)) val data = ByteBuffer.allocate(16) @@ -156,7 +153,7 @@ object Identifier { data.putLong(lowPart) Identifier(string, data.array()) - } getOrElse(Empty) + } getOrElse (Empty) override def from(bytes: Array[Byte]): Identifier = Try { val buffer = ByteBuffer.wrap(bytes) @@ -164,7 +161,7 @@ object Identifier { val lowLong = buffer.getLong Identifier(HexCodec.toLowerHex(highLong) + HexCodec.toLowerHex(lowLong), bytes) - } getOrElse(Empty) + } getOrElse (Empty) } } diff --git a/core/kamon-core/src/main/scala/kamon/trace/RandomSampler.scala b/core/kamon-core/src/main/scala/kamon/trace/RandomSampler.scala index f7c4a43c8..dcea2f59a 100644 --- a/core/kamon-core/src/main/scala/kamon/trace/RandomSampler.scala +++ b/core/kamon-core/src/main/scala/kamon/trace/RandomSampler.scala @@ -24,7 +24,7 @@ import kamon.trace.Trace.SamplingDecision /** * Sampler that uses a random number generator and a probability threshold to decide whether to trace a request or not. */ -class RandomSampler private(probability: Double) extends Sampler { +class RandomSampler private (probability: Double) extends Sampler { private val _upperBoundary = Long.MaxValue * probability private val _lowerBoundary = -_upperBoundary private val _affirmativeDecisionCounter = Sampler.Metrics.samplingDecisions("random", SamplingDecision.Sample) @@ -32,7 +32,7 @@ class RandomSampler private(probability: Double) extends Sampler { override def decide(operation: Sampler.Operation): SamplingDecision = { val random = ThreadLocalRandom.current().nextLong() - if(random >= _lowerBoundary && random <= _upperBoundary) { + if (random >= _lowerBoundary && random <= _upperBoundary) { _affirmativeDecisionCounter.increment() SamplingDecision.Sample } else { @@ -52,7 +52,7 @@ object RandomSampler { * adjusted to 1D and if it is lower than 0 it will be adjusted to 0. */ def apply(probability: Double): RandomSampler = { - val sanitizedProbability = if(probability > 1D) 1D else if (probability < 0D) 0D else probability + val sanitizedProbability = if (probability > 1d) 1d else if (probability < 0d) 0d else probability new RandomSampler(sanitizedProbability) } diff --git a/core/kamon-core/src/main/scala/kamon/trace/Sampler.scala b/core/kamon-core/src/main/scala/kamon/trace/Sampler.scala index f644b5233..c2535f4c0 100644 --- a/core/kamon-core/src/main/scala/kamon/trace/Sampler.scala +++ b/core/kamon-core/src/main/scala/kamon/trace/Sampler.scala @@ -70,4 +70,4 @@ object Sampler { def operationName(): String } -} \ No newline at end of file +} diff --git a/core/kamon-core/src/main/scala/kamon/trace/Span.scala b/core/kamon-core/src/main/scala/kamon/trace/Span.scala index 6efb3bb8c..7c01c47dc 100644 --- a/core/kamon-core/src/main/scala/kamon/trace/Span.scala +++ b/core/kamon-core/src/main/scala/kamon/trace/Span.scala @@ -87,6 +87,7 @@ sealed abstract class Span extends Sampler.Operation { * Returns true if this Span is a placeholder because no Span information is available. */ def isEmpty: Boolean + /** * Returns the position of this Span in the trace to which it belongs. */ @@ -307,7 +308,6 @@ object Span { override def toString: String = "producer" } - /** * The Span represents an operation that consumes messages from a message broker. */ @@ -333,7 +333,6 @@ object Span { } } - /** * Describes a Span's position within the trace they belong to. */ @@ -387,7 +386,7 @@ object Span { /** * Represents a Span that has already been finished and should be exposed to the SpanReporters. */ - case class Finished ( + case class Finished( id: Identifier, trace: Trace, parentId: Identifier, @@ -407,13 +406,34 @@ object Span { /** * A writable Span created on this process and implementing all the capabilities defined by the Span interface. */ - final class Local(val id: Identifier, val parentId: Identifier, val trace: Trace, val position: Position, - val kind: Kind, localParent: Option[Span], initialOperationName: String, spanTags: TagSet.Builder, metricTags: TagSet.Builder, - createdAt: Instant, initialMarks: List[Mark], initialLinks: List[Link], initialTrackMetrics: Boolean, tagWithParentOperation: Boolean, - includeErrorStacktrace: Boolean, isDelayed: Boolean, clock: Clock, preFinishHooks: Array[Tracer.PreFinishHook], - onFinish: Span.Finished => Unit, sampler: Sampler, scheduler: ScheduledExecutorService, reportingDelay: Duration, - localTailSamplerSettings: LocalTailSamplerSettings, includeErrorType: Boolean, ignoredOperations: Set[String], - trackMetricsOnIgnoredOperations: Boolean) extends Span.Delayed { + final class Local( + val id: Identifier, + val parentId: Identifier, + val trace: Trace, + val position: Position, + val kind: Kind, + localParent: Option[Span], + initialOperationName: String, + spanTags: TagSet.Builder, + metricTags: TagSet.Builder, + createdAt: Instant, + initialMarks: List[Mark], + initialLinks: List[Link], + initialTrackMetrics: Boolean, + tagWithParentOperation: Boolean, + includeErrorStacktrace: Boolean, + isDelayed: Boolean, + clock: Clock, + preFinishHooks: Array[Tracer.PreFinishHook], + onFinish: Span.Finished => Unit, + sampler: Sampler, + scheduler: ScheduledExecutorService, + reportingDelay: Duration, + localTailSamplerSettings: LocalTailSamplerSettings, + includeErrorType: Boolean, + ignoredOperations: Set[String], + trackMetricsOnIgnoredOperations: Boolean + ) extends Span.Delayed { private val _metricTags = metricTags private val _spanTags = spanTags @@ -434,7 +454,7 @@ object Span { start(clock.instant()) override def start(at: Instant): Delayed = synchronized { - if(_isOpen && isDelayed && !_isDelayedStarted) { + if (_isOpen && isDelayed && !_isDelayedStarted) { _startedAt = at _isDelayedStarted = true mark(MarkKeys.SpanStarted, at) @@ -443,49 +463,49 @@ object Span { } override def tag(key: String, value: String): Span = synchronized { - if((isSampled || !reportingDelay.isZero) && _isOpen) + if ((isSampled || !reportingDelay.isZero) && _isOpen) _spanTags.add(key, value) this } override def tag(key: String, value: Long): Span = synchronized { - if((isSampled || !reportingDelay.isZero) && _isOpen) + if ((isSampled || !reportingDelay.isZero) && _isOpen) _spanTags.add(key, value) this } override def tag(key: String, value: Boolean): Span = synchronized { - if((isSampled || !reportingDelay.isZero) && _isOpen) + if ((isSampled || !reportingDelay.isZero) && _isOpen) _spanTags.add(key, value) this } override def tag(tags: TagSet): Span = synchronized { - if((isSampled || !reportingDelay.isZero) && _isOpen) + if ((isSampled || !reportingDelay.isZero) && _isOpen) _spanTags.add(tags) this } override def tagMetrics(key: String, value: String): Span = synchronized { - if(_isOpen && _trackMetrics) + if (_isOpen && _trackMetrics) _metricTags.add(key, value) this } override def tagMetrics(key: String, value: Long): Span = synchronized { - if(_isOpen && _trackMetrics) + if (_isOpen && _trackMetrics) _metricTags.add(key, value) this } override def tagMetrics(key: String, value: Boolean): Span = synchronized { - if(_isOpen && _trackMetrics) + if (_isOpen && _trackMetrics) _metricTags.add(key, value) this } override def tagMetrics(tags: TagSet): Span = synchronized { - if(_isOpen && _trackMetrics) + if (_isOpen && _trackMetrics) _metricTags.add(tags) this } @@ -495,37 +515,37 @@ object Span { } override def mark(key: String, at: Instant): Span = synchronized { - if(_isOpen) + if (_isOpen) _marks = Mark(at, key) :: _marks this } override def link(span: Span, kind: Link.Kind): Span = synchronized { - if(_isOpen) + if (_isOpen) _links = Link(kind, span.trace, span.id) :: _links this } override def fail(message: String): Span = synchronized { - if(_isOpen) { + if (_isOpen) { _hasError = true trace.spanFailed() - if((isSampled || !reportingDelay.isZero)) + if ((isSampled || !reportingDelay.isZero)) _spanTags.add(TagKeys.ErrorMessage, message) } this } override def fail(throwable: Throwable): Span = synchronized { - if(_isOpen) { + if (_isOpen) { _hasError = true trace.spanFailed() - if((isSampled || !reportingDelay.isZero)) { + if ((isSampled || !reportingDelay.isZero)) { _spanTags.add(TagKeys.ErrorMessage, throwable.getMessage) - if(includeErrorStacktrace) + if (includeErrorStacktrace) _spanTags.add(TagKeys.ErrorStacktrace, toStackTraceString(throwable)) if (includeErrorType) @@ -536,14 +556,14 @@ object Span { } override def fail(message: String, throwable: Throwable): Span = synchronized { - if(_isOpen) { + if (_isOpen) { _hasError = true trace.spanFailed() - if((isSampled || !reportingDelay.isZero)) { + if ((isSampled || !reportingDelay.isZero)) { _spanTags.add(TagKeys.ErrorMessage, message) - if(includeErrorStacktrace) + if (includeErrorStacktrace) _spanTags.add(TagKeys.ErrorStacktrace, toStackTraceString(throwable)) if (includeErrorType) @@ -563,29 +583,28 @@ object Span { this } - override def trackDelayedSpanMetrics(): Delayed = synchronized { + override def trackDelayedSpanMetrics(): Delayed = synchronized { _trackDelayedSpanMetrics = true this } - override def doNotTrackDelayedSpanMetrics(): Delayed = synchronized { + override def doNotTrackDelayedSpanMetrics(): Delayed = synchronized { _trackDelayedSpanMetrics = false this } override def takeSamplingDecision(): Span = synchronized { - if(trace.samplingDecision == SamplingDecision.Unknown) { - if(ignoredOperations.contains(operationName())) { - if(!trackMetricsOnIgnoredOperations) + if (trace.samplingDecision == SamplingDecision.Unknown) { + if (ignoredOperations.contains(operationName())) { + if (!trackMetricsOnIgnoredOperations) doNotTrackMetrics() trace.drop() - } - else { + } else { sampler.decide(this) match { - case SamplingDecision.Sample => trace.keep() + case SamplingDecision.Sample => trace.keep() case SamplingDecision.DoNotSample => trace.drop() - case SamplingDecision.Unknown => // We should never get to this point! + case SamplingDecision.Unknown => // We should never get to this point! } } } @@ -598,7 +617,7 @@ object Span { } override def name(operationName: String): Span = synchronized { - if(_isOpen) + if (_isOpen) _operationName = operationName this } @@ -613,7 +632,7 @@ object Span { if (_isOpen) { - if(preFinishHooks.nonEmpty) { + if (preFinishHooks.nonEmpty) { preFinishHooks.foreach(pfh => { try { pfh.beforeFinish(this) @@ -638,12 +657,26 @@ object Span { throwable.getStackTrace().mkString("", EOL, EOL) protected def toFinishedSpan(to: Instant, metricTags: TagSet): Span.Finished = - Span.Finished(id, trace, parentId, _operationName, _hasError, isDelayed, createdAt, to, kind, position, _spanTags.build(), - metricTags, _marks, _links) + Span.Finished( + id, + trace, + parentId, + _operationName, + _hasError, + isDelayed, + createdAt, + to, + kind, + position, + _spanTags.build(), + metricTags, + _marks, + _links + ) private def recordSpanMetrics(finishedAt: Instant, metricTags: TagSet): Unit = { - if(_trackMetrics) { - if(!isDelayed) { + if (_trackMetrics) { + if (!isDelayed) { val processingTime = Clock.nanosBetween(createdAt, finishedAt) Span.Metrics.ProcessingTime.withTags(metricTags).record(processingTime) @@ -667,18 +700,18 @@ object Span { if (isRootSpan && localTailSamplerSettings.enabled) { val hasEnoughErrors = trace.failedSpansCount() >= localTailSamplerSettings.errorCountThreshold - val hasEnoughLatency = Clock.nanosBetween(_startedAt, finishedAt) >= localTailSamplerSettings.latencyThresholdNanos + val hasEnoughLatency = + Clock.nanosBetween(_startedAt, finishedAt) >= localTailSamplerSettings.latencyThresholdNanos if (hasEnoughErrors || hasEnoughLatency) { trace.keep() } } - if(reportingDelay.isZero) { - if(isSampled) + if (reportingDelay.isZero) { + if (isSampled) onFinish(toFinishedSpan(finishedAt, metricTags)) - } - else { + } else { scheduler.schedule( new DelayedReportingRunnable(finishedAt, metricTags), reportingDelay.toMillis, @@ -687,18 +720,17 @@ object Span { } } - private def createMetricTags(): TagSet = { _metricTags.add(TagKeys.OperationName, _operationName) _metricTags.add(TagKeys.Error, _hasError) - if(kind != Span.Kind.Unknown) + if (kind != Span.Kind.Unknown) _metricTags.add(TagKeys.SpanKind, kind.toString) - if(tagWithParentOperation) + if (tagWithParentOperation) localParent.foreach { - case p: Span.Local => _metricTags.add(TagKeys.ParentOperationName, p.operationName()) - case _ => // Can't get an operation name from anything else than a local span. + case p: Span.Local => _metricTags.add(TagKeys.ParentOperationName, p.operationName()) + case _ => // Can't get an operation name from anything else than a local span. } _metricTags.build() @@ -758,7 +790,6 @@ object Span { override def start(at: Instant): Delayed = this } - /** * A immutable, no-op Span that holds information from a Span that was initially created in another process and then * transferred to this process. This is the minimal representation of a Span that gets transferred through Context @@ -794,29 +825,27 @@ object Span { override def toString(): String = s"Span.Remote{id=${id.string},parentId=${parentId.string},trace=${trace}" } - /** * Metrics tracked by the Span implementation. */ object Metrics { - val ProcessingTime = Kamon.timer ( + val ProcessingTime = Kamon.timer( name = "span.processing-time", description = "Tracks the time between the instant a Span started and finished processing" ) - val ElapsedTime = Kamon.timer ( + val ElapsedTime = Kamon.timer( name = "span.elapsed-time", description = "Tracks the total elapsed time between the instant a Span was created until it finishes processing" ) - val WaitTime = Kamon.timer ( + val WaitTime = Kamon.timer( name = "span.wait-time", description = "Tracks the waiting time between creation of a delayed Span and the instant it starts processing" ) } - /** * Tag keys used by the implementations to record Span and metric tags. */ diff --git a/core/kamon-core/src/main/scala/kamon/trace/SpanPropagation.scala b/core/kamon-core/src/main/scala/kamon/trace/SpanPropagation.scala index 77034f739..f885a87bf 100644 --- a/core/kamon-core/src/main/scala/kamon/trace/SpanPropagation.scala +++ b/core/kamon-core/src/main/scala/kamon/trace/SpanPropagation.scala @@ -28,7 +28,6 @@ import java.lang.{Long => JLong} import scala.util.Try - /** * Propagation mechanisms for Kamon's Span data to and from HTTP and Binary mediums. */ @@ -70,47 +69,48 @@ object SpanPropagation { } } -object W3CTraceContext { - val Version: String = "00" - val TraceStateKey: Context.Key[String] = Context.key("tracestate", "") + object W3CTraceContext { + val Version: String = "00" + val TraceStateKey: Context.Key[String] = Context.key("tracestate", "") - object Headers { - val TraceParent = "traceparent" - val TraceState = "tracestate" - } + object Headers { + val TraceParent = "traceparent" + val TraceState = "tracestate" + } - def apply(): W3CTraceContext = - new W3CTraceContext() + def apply(): W3CTraceContext = + new W3CTraceContext() - def decodeTraceParent(traceParent: String): Option[Span] = { - val identityProvider = Identifier.Scheme.Double + def decodeTraceParent(traceParent: String): Option[Span] = { + val identityProvider = Identifier.Scheme.Double - def unpackSamplingDecision(decision: String): SamplingDecision = - if ("01" == decision) SamplingDecision.Sample else SamplingDecision.Unknown + def unpackSamplingDecision(decision: String): SamplingDecision = + if ("01" == decision) SamplingDecision.Sample else SamplingDecision.Unknown - val traceParentComponents = traceParent.split("-") + val traceParentComponents = traceParent.split("-") - if (traceParentComponents.length != 4) None else { - val spanID = identityProvider.spanIdFactory.from(traceParentComponents(2)) - val traceID = identityProvider.traceIdFactory.from(traceParentComponents(1)) - val parentSpanID = Identifier.Empty - val samplingDecision = unpackSamplingDecision(traceParentComponents(3)) + if (traceParentComponents.length != 4) None + else { + val spanID = identityProvider.spanIdFactory.from(traceParentComponents(2)) + val traceID = identityProvider.traceIdFactory.from(traceParentComponents(1)) + val parentSpanID = Identifier.Empty + val samplingDecision = unpackSamplingDecision(traceParentComponents(3)) - Some(Span.Remote(spanID, parentSpanID, Trace(traceID, samplingDecision))) + Some(Span.Remote(spanID, parentSpanID, Trace(traceID, samplingDecision))) + } } - } - def encodeTraceParent(parent: Span): String = { - def idToHex(identifier: Identifier, length: Int): String = { - val leftPad = (string: String) => "0" * (length - string.length) + string - leftPad(identifier.bytes.map("%02x" format _).mkString) - } + def encodeTraceParent(parent: Span): String = { + def idToHex(identifier: Identifier, length: Int): String = { + val leftPad = (string: String) => "0" * (length - string.length) + string + leftPad(identifier.bytes.map("%02x" format _).mkString) + } - val samplingDecision = if (parent.trace.samplingDecision == SamplingDecision.Sample) "01" else "00" + val samplingDecision = if (parent.trace.samplingDecision == SamplingDecision.Sample) "01" else "00" - s"$Version-${idToHex(parent.trace.id, 32)}-${idToHex(parent.id, 16)}-${samplingDecision}" + s"$Version-${idToHex(parent.trace.id, 32)}-${idToHex(parent.id, 16)}-${samplingDecision}" + } } -} /** * Reads and Writes a Span instance using the B3 propagation format. The specification and semantics of the B3 @@ -129,7 +129,7 @@ object W3CTraceContext { .map(id => identifierScheme.spanIdFactory.from(urlDecode(id))) .getOrElse(Identifier.Empty) - if(traceID != Identifier.Empty && spanID != Identifier.Empty) { + if (traceID != Identifier.Empty && spanID != Identifier.Empty) { val parentID = reader.read(Headers.ParentSpanIdentifier) .map(id => identifierScheme.spanIdFactory.from(urlDecode(id))) .getOrElse(Identifier.Empty) @@ -142,7 +142,7 @@ object W3CTraceContext { reader.read(Headers.Sampled) match { case Some(sampled) if sampled == "1" => SamplingDecision.Sample case Some(sampled) if sampled == "0" => SamplingDecision.DoNotSample - case _ => SamplingDecision.Unknown + case _ => SamplingDecision.Unknown } } @@ -154,11 +154,11 @@ object W3CTraceContext { override def write(context: Context, writer: HttpPropagation.HeaderWriter): Unit = { val span = context.get(Span.Key) - if(span != Span.Empty) { + if (span != Span.Empty) { writer.write(Headers.TraceIdentifier, urlEncode(span.trace.id.string)) writer.write(Headers.SpanIdentifier, urlEncode(span.id.string)) - if(span.parentId != Identifier.Empty) + if (span.parentId != Identifier.Empty) writer.write(Headers.ParentSpanIdentifier, urlEncode(span.parentId.string)) encodeSamplingDecision(span.trace.samplingDecision).foreach { samplingDecision => @@ -217,8 +217,8 @@ object W3CTraceContext { val sd = samplingDecision match { case Some(sampled) if sampled == "1" || sampled.equalsIgnoreCase("d") => SamplingDecision.Sample - case Some(sampled) if sampled == "0" => SamplingDecision.DoNotSample - case _ => SamplingDecision.Unknown + case Some(sampled) if sampled == "0" => SamplingDecision.DoNotSample + case _ => SamplingDecision.Unknown } context.withEntry(Span.Key, new Span.Remote(si, parentID, Trace(ti, sd))) @@ -229,7 +229,7 @@ object W3CTraceContext { override def write(context: Context, writer: HttpPropagation.HeaderWriter): Unit = { val span = context.get(Span.Key) - if(span != Span.Empty) { + if (span != Span.Empty) { val buffer = new StringBuilder() val traceId = urlEncode(span.trace.id.string) val spanId = urlEncode(span.id.string) @@ -239,14 +239,13 @@ object W3CTraceContext { encodeSamplingDecision(span.trace.samplingDecision) .foreach(samplingDecision => buffer.append("-").append(samplingDecision)) - if(span.parentId != Identifier.Empty) + if (span.parentId != Identifier.Empty) buffer.append("-").append(urlEncode(span.parentId.string)) writer.write(Header.B3, buffer.toString) } } - private def encodeSamplingDecision(samplingDecision: SamplingDecision): Option[String] = samplingDecision match { case SamplingDecision.Sample => Some("1") case SamplingDecision.DoNotSample => Some("0") @@ -264,8 +263,8 @@ object W3CTraceContext { def splitToTuple(regex: String): (Option[String], Option[String], Option[String], Option[String]) = { s.split(regex) match { case Array(str1, str2, str3, str4) => (Option(str1), Option(str2), Option(str3), Option(str4)) - case Array(str1, str2, str3) => (Option(str1), Option(str2), Option(str3), None) - case Array(str1, str2) => (Option(str1), Option(str2), None, None) + case Array(str1, str2, str3) => (Option(str1), Option(str2), Option(str3), None) + case Array(str1, str2) => (Option(str1), Option(str2), None, None) } } } @@ -274,7 +273,6 @@ object W3CTraceContext { new B3Single() } - /** * Reads and Writes a Span instance using the jaeger single-header propagation format. * The specification and semantics can be found here: @@ -364,28 +362,31 @@ object W3CTraceContext { class Colfer extends Propagation.EntryReader[ByteStreamReader] with Propagation.EntryWriter[ByteStreamWriter] { override def read(medium: ByteStreamReader, context: Context): Context = { - if(medium.available() == 0) + if (medium.available() == 0) context else { val identityProvider = Kamon.identifierScheme val colferSpan = new ColferSpan() colferSpan.unmarshal(medium.readAll(), 0) - context.withEntry(Span.Key, new Span.Remote( - id = identityProvider.spanIdFactory.from(colferSpan.spanID), - parentId = identityProvider.spanIdFactory.from(colferSpan.parentID), - trace = Trace( - id = identityProvider.traceIdFactory.from(colferSpan.traceID), - samplingDecision = byteToSamplingDecision(colferSpan.samplingDecision) + context.withEntry( + Span.Key, + new Span.Remote( + id = identityProvider.spanIdFactory.from(colferSpan.spanID), + parentId = identityProvider.spanIdFactory.from(colferSpan.parentID), + trace = Trace( + id = identityProvider.traceIdFactory.from(colferSpan.traceID), + samplingDecision = byteToSamplingDecision(colferSpan.samplingDecision) + ) ) - )) + ) } } override def write(context: Context, medium: ByteStreamWriter): Unit = { val span = context.get(Span.Key) - if(span != Span.Empty) { + if (span != Span.Empty) { val marshalBuffer = Colfer.codecBuffer.get() val colferSpan = new ColferSpan() @@ -474,9 +475,9 @@ object W3CTraceContext { val samplingDecision = reader.read(Headers.SamplingPriority) match { - case Some(SamplingPriority.Sample) => SamplingDecision.Sample + case Some(SamplingPriority.Sample) => SamplingDecision.Sample case Some(SamplingPriority.DoNotSample) => SamplingDecision.DoNotSample - case _ => SamplingDecision.Unknown + case _ => SamplingDecision.Unknown } context.withEntry(Span.Key, Span.Remote(spanId, parentId, Trace(traceId, samplingDecision))) @@ -494,7 +495,7 @@ object W3CTraceContext { SamplingPriority.Sample else SamplingPriority.DoNotSample - writer.write(Headers.SamplingPriority,decision) + writer.write(Headers.SamplingPriority, decision) } } } diff --git a/core/kamon-core/src/main/scala/kamon/trace/Trace.scala b/core/kamon-core/src/main/scala/kamon/trace/Trace.scala index 0d71ac1cd..1d7cc08cf 100644 --- a/core/kamon-core/src/main/scala/kamon/trace/Trace.scala +++ b/core/kamon-core/src/main/scala/kamon/trace/Trace.scala @@ -90,7 +90,6 @@ object Trace { def create(id: Identifier, samplingDecision: SamplingDecision): Trace = new MutableTrace(id, samplingDecision) - private class MutableTrace(val id: Identifier, initialDecision: Trace.SamplingDecision) extends Trace { @volatile private var _samplingDecision = initialDecision @volatile private var _failedSpansCount = new AtomicInteger(0) diff --git a/core/kamon-core/src/main/scala/kamon/trace/Tracer.scala b/core/kamon-core/src/main/scala/kamon/trace/Tracer.scala index 2fa1055f7..cef3075a1 100644 --- a/core/kamon-core/src/main/scala/kamon/trace/Tracer.scala +++ b/core/kamon-core/src/main/scala/kamon/trace/Tracer.scala @@ -32,7 +32,6 @@ import org.slf4j.LoggerFactory import scala.collection.JavaConverters.collectionAsScalaIterableConverter - /** * A Tracer assists on the creation of Spans and temporarily holds finished Spans until they are flushed to the * available reporters. @@ -52,7 +51,8 @@ class Tracer(initialConfig: Config, clock: Clock, contextStorage: ContextStorage @volatile private var _preStartHooks: Array[Tracer.PreStartHook] = Array.empty @volatile private var _preFinishHooks: Array[Tracer.PreFinishHook] = Array.empty @volatile private var _delayedSpanReportingDelay: Duration = Duration.ZERO - @volatile private var _localTailSamplerSettings: LocalTailSamplerSettings = LocalTailSamplerSettings(false, Int.MaxValue, Long.MaxValue) + @volatile private var _localTailSamplerSettings: LocalTailSamplerSettings = + LocalTailSamplerSettings(false, Int.MaxValue, Long.MaxValue) @volatile private var _scheduler: Option[ScheduledExecutorService] = None @volatile private var _includeErrorType: Boolean = false @volatile private var _ignoredOperations: Set[String] = Set.empty @@ -61,14 +61,12 @@ class Tracer(initialConfig: Config, clock: Clock, contextStorage: ContextStorage reconfigure(initialConfig) - /** * Returns the Identifier Scheme currently used by the tracer. */ def identifierScheme: Identifier.Scheme = _identifierScheme - /** * Creates a new SpanBuilder for a Server Span and applies the provided component name as a metric tag. It is * recommended that all Spans include a "component" metric tag that indicates what library or library section is @@ -77,7 +75,6 @@ class Tracer(initialConfig: Config, clock: Clock, contextStorage: ContextStorage def serverSpanBuilder(operationName: String, component: String): SpanBuilder = spanBuilder(operationName).kind(Kind.Server).tagMetrics(Span.TagKeys.Component, component) - /** * Creates a new SpanBuilder for a Client Span and applies the provided component name as a metric tag. It is * recommended that all Spans include a "component" metric tag that indicates what library or library section is @@ -86,7 +83,6 @@ class Tracer(initialConfig: Config, clock: Clock, contextStorage: ContextStorage def clientSpanBuilder(operationName: String, component: String): SpanBuilder = spanBuilder(operationName).kind(Kind.Client).tagMetrics(Span.TagKeys.Component, component) - /** * Creates a new SpanBuilder for a Producer Span and applies the provided component name as a metric tag. It is * recommended that all Spans include a "component" metric tag that indicates what library or library section is @@ -95,7 +91,6 @@ class Tracer(initialConfig: Config, clock: Clock, contextStorage: ContextStorage def producerSpanBuilder(operationName: String, component: String): SpanBuilder = spanBuilder(operationName).kind(Kind.Producer).tagMetrics(Span.TagKeys.Component, component) - /** * Creates a new SpanBuilder for a Consumer Span and applies the provided component name as a metric tag. It is * recommended that all Spans include a "component" metric tag that indicates what library or library section is @@ -104,7 +99,6 @@ class Tracer(initialConfig: Config, clock: Clock, contextStorage: ContextStorage def consumerSpanBuilder(operationName: String, component: String): SpanBuilder = spanBuilder(operationName).kind(Kind.Consumer).tagMetrics(Span.TagKeys.Component, component) - /** * Creates a new SpanBuilder for an Internal Span and applies the provided component name as a metric tag. It is * recommended that all Spans include a "component" metric tag that indicates what library or library section is @@ -113,7 +107,6 @@ class Tracer(initialConfig: Config, clock: Clock, contextStorage: ContextStorage def internalSpanBuilder(operationName: String, component: String): SpanBuilder = spanBuilder(operationName).kind(Kind.Internal).tagMetrics(Span.TagKeys.Component, component) - /** * Creates a new raw SpanBuilder instance using the provided operation name. */ @@ -143,8 +136,6 @@ class Tracer(initialConfig: Config, clock: Clock, contextStorage: ContextStorage _adaptiveSamplerSchedule.foreach(_.cancel(false)) } - - private class MutableSpanBuilder(initialOperationName: String) extends SpanBuilder { private val _spanTags = TagSet.builder() private val _metricTags = TagSet.builder() @@ -301,10 +292,9 @@ class Tracer(initialConfig: Config, clock: Clock, contextStorage: ContextStorage // Having a scheduler is a proxy to knowing whether Kamon has been initialized or not. We might consider // introducing some sort if "isActive" state if we start having more variables that only need to be defined // when Kamon has started. - if(_scheduler.isEmpty) { + if (_scheduler.isEmpty) { Span.Empty - } - else { + } else { if (_preStartHooks.nonEmpty) { _preStartHooks.foreach(psh => { try { @@ -316,8 +306,7 @@ class Tracer(initialConfig: Config, clock: Clock, contextStorage: ContextStorage }) } - - val context = _context.getOrElse(contextStorage.currentContext()) + val context = _context.getOrElse(contextStorage.currentContext()) if (_tagWithUpstreamService) { context.getTag(option(TagKeys.UpstreamName)).foreach(upstreamName => { _metricTags.add(TagKeys.UpstreamName, upstreamName) @@ -354,9 +343,9 @@ class Tracer(initialConfig: Config, clock: Clock, contextStorage: ContextStorage // set on the SpanBuilder. if (parent.isRemote && parent.trace.samplingDecision == SamplingDecision.Unknown) { suggestedOrSamplerDecision() match { - case SamplingDecision.Sample => parent.trace.keep() + case SamplingDecision.Sample => parent.trace.keep() case SamplingDecision.DoNotSample => parent.trace.drop() - case SamplingDecision.Unknown => // Nothing to do in this case. + case SamplingDecision.Unknown => // Nothing to do in this case. } } @@ -364,16 +353,40 @@ class Tracer(initialConfig: Config, clock: Clock, contextStorage: ContextStorage } } - new Span.Local(id, parentId, trace, position, _kind, localParent, _name, _spanTags, _metricTags, at, _marks, _links, - _trackMetrics, _tagWithParentOperation, _includeErrorStacktrace, isDelayed, clock, _preFinishHooks, _onSpanFinish, - _sampler, _scheduler.get, _delayedSpanReportingDelay, _localTailSamplerSettings, _includeErrorType, - _ignoredOperations, _trackMetricsOnIgnoredOperations) + new Span.Local( + id, + parentId, + trace, + position, + _kind, + localParent, + _name, + _spanTags, + _metricTags, + at, + _marks, + _links, + _trackMetrics, + _tagWithParentOperation, + _includeErrorStacktrace, + isDelayed, + clock, + _preFinishHooks, + _onSpanFinish, + _sampler, + _scheduler.get, + _delayedSpanReportingDelay, + _localTailSamplerSettings, + _includeErrorType, + _ignoredOperations, + _trackMetricsOnIgnoredOperations + ) } } private def suggestedOrSamplerDecision(): SamplingDecision = { - if(_ignoredOperations.contains(_name)) { - if(!_trackMetricsOnIgnoredOperations) + if (_ignoredOperations.contains(_name)) { + if (!_trackMetricsOnIgnoredOperations) doNotTrackMetrics() SamplingDecision.DoNotSample @@ -382,10 +395,9 @@ class Tracer(initialConfig: Config, clock: Clock, contextStorage: ContextStorage } private def suggestedOrGeneratedTraceId(): Identifier = - if(_suggestedTraceId.isEmpty) identifierScheme.traceIdFactory.generate() else _suggestedTraceId + if (_suggestedTraceId.isEmpty) identifierScheme.traceIdFactory.generate() else _suggestedTraceId } - /** * Applies a new configuration to the tracer and its related components. */ @@ -393,36 +405,42 @@ class Tracer(initialConfig: Config, clock: Clock, contextStorage: ContextStorage try { val traceConfig = newConfig.getConfig("kamon.trace") val sampler = traceConfig.getString("sampler") match { - case "always" => ConstantSampler.Always - case "never" => ConstantSampler.Never - case "random" => RandomSampler(traceConfig.getDouble("random-sampler.probability")) - case "adaptive" => AdaptiveSampler() - case fqcn => - + case "always" => ConstantSampler.Always + case "never" => ConstantSampler.Never + case "random" => RandomSampler(traceConfig.getDouble("random-sampler.probability")) + case "adaptive" => AdaptiveSampler() + case fqcn => // We assume that any other value must be a FQCN of a Sampler implementation and try to build an // instance from it. - try ClassLoading.createInstance[Sampler](fqcn) catch { + try ClassLoading.createInstance[Sampler](fqcn) + catch { case t: Throwable => - _logger.error(s"Failed to create sampler instance from FQCN [$fqcn], falling back to random sampling with 10% probability", t) - RandomSampler(0.1D) + _logger.error( + s"Failed to create sampler instance from FQCN [$fqcn], falling back to random sampling with 10% probability", + t + ) + RandomSampler(0.1d) } } val identifierScheme = traceConfig.getString("identifier-scheme") match { case "single" => Identifier.Scheme.Single case "double" => Identifier.Scheme.Double - case fqcn => - + case fqcn => // We assume that any other value must be a FQCN of an Identifier Scheme implementation and try to build an // instance from it. - try ClassLoading.createInstance[Identifier.Scheme](fqcn) catch { + try ClassLoading.createInstance[Identifier.Scheme](fqcn) + catch { case t: Throwable => - _logger.error(s"Failed to create identifier scheme instance from FQCN [$fqcn], falling back to the single scheme", t) + _logger.error( + s"Failed to create identifier scheme instance from FQCN [$fqcn], falling back to the single scheme", + t + ) Identifier.Scheme.Single } } - if(sampler.isInstanceOf[AdaptiveSampler]) { + if (sampler.isInstanceOf[AdaptiveSampler]) { schedulerAdaptiveSampling() } else { _adaptiveSamplerSchedule.foreach(_.cancel(false)) @@ -450,13 +468,14 @@ class Tracer(initialConfig: Config, clock: Clock, contextStorage: ContextStorage latencyThresholdNanos = traceConfig.getDuration("local-tail-sampler.latency-threshold").toNanos ) - if(localTailSamplerSettings.enabled && delayedSpanReportingDelay.isZero) { + if (localTailSamplerSettings.enabled && delayedSpanReportingDelay.isZero) { _logger.warn( "Enabling local tail sampling without a span-reporting-delay setting will probably lead to incomplete " + - "traces. Consider setting span-reporting-delay to a value slightly above your application's requests timeout") + "traces. Consider setting span-reporting-delay to a value slightly above your application's requests timeout" + ) } - if(_traceReporterQueueSize != traceReporterQueueSize) { + if (_traceReporterQueueSize != traceReporterQueueSize) { // By simply changing the buffer we might be dropping Spans that have not been collected yet by the reporters. // Since reconfigures are very unlikely to happen beyond application startup this might not be a problem. // If we eventually decide to keep those possible Spans around then we will need to change the queue type to @@ -485,9 +504,12 @@ class Tracer(initialConfig: Config, clock: Clock, contextStorage: ContextStorage } private def schedulerAdaptiveSampling(): Unit = { - if(_sampler.isInstanceOf[AdaptiveSampler] && _adaptiveSamplerSchedule.isEmpty && _scheduler.nonEmpty) + if (_sampler.isInstanceOf[AdaptiveSampler] && _adaptiveSamplerSchedule.isEmpty && _scheduler.nonEmpty) _adaptiveSamplerSchedule = Some(_scheduler.get.scheduleAtFixedRate( - adaptiveSamplerAdaptRunnable(), 1, 1, TimeUnit.SECONDS + adaptiveSamplerAdaptRunnable(), + 1, + 1, + TimeUnit.SECONDS )) } @@ -495,7 +517,7 @@ class Tracer(initialConfig: Config, clock: Clock, contextStorage: ContextStorage override def run(): Unit = { _sampler match { case adaptiveSampler: AdaptiveSampler => adaptiveSampler.adapt() - case _ => // just ignore any other sampler type. + case _ => // just ignore any other sampler type. } } } @@ -512,7 +534,6 @@ object Tracer { def beforeStart(builder: SpanBuilder): Unit } - /** * A callback function that is applied to all Span instances right before they are finished and flushed to Span * reporters. PreFinishHook implementations are configured using the "kamon.trace.hooks.pre-finish" configuration diff --git a/core/kamon-core/src/main/scala/kamon/util/CallingThreadExecutionContext.scala b/core/kamon-core/src/main/scala/kamon/util/CallingThreadExecutionContext.scala index 5167614dc..768ce4800 100644 --- a/core/kamon-core/src/main/scala/kamon/util/CallingThreadExecutionContext.scala +++ b/core/kamon-core/src/main/scala/kamon/util/CallingThreadExecutionContext.scala @@ -35,4 +35,4 @@ object CallingThreadExecutionContext extends ExecutionContext with Executor { override def reportFailure(t: Throwable): Unit = _logger.error(t.getMessage, t) -} \ No newline at end of file +} diff --git a/core/kamon-core/src/main/scala/kamon/util/Clock.scala b/core/kamon-core/src/main/scala/kamon/util/Clock.scala index a05592e9e..dc82d4c58 100644 --- a/core/kamon-core/src/main/scala/kamon/util/Clock.scala +++ b/core/kamon-core/src/main/scala/kamon/util/Clock.scala @@ -62,16 +62,16 @@ object Clock { var nanos = System.nanoTime() var isCandidate = false - while(calibrationIterations > 0) { + while (calibrationIterations > 0) { val currentMillis = System.currentTimeMillis() val currentNanos = System.nanoTime() - if(isCandidate && millis != currentMillis) { + if (isCandidate && millis != currentMillis) { millis = currentMillis nanos = currentNanos calibrationIterations = 0 } else { - if(millis == currentMillis) { + if (millis == currentMillis) { isCandidate = true } else { millis = currentMillis @@ -86,7 +86,8 @@ object Clock { } private val _startSecondTime = Math.floorDiv(_startTimeMillis, _millisInSecond) - private val _startSecondNanoOffset = Math.multiplyExact(Math.floorMod(_startTimeMillis, _millisInSecond), _microsInSecond) + private val _startSecondNanoOffset = + Math.multiplyExact(Math.floorMod(_startTimeMillis, _millisInSecond), _microsInSecond) override def nanos(): Long = System.nanoTime() @@ -138,4 +139,4 @@ object Clock { Instant.ofEpochMilli(nextTickMillis) } -} \ No newline at end of file +} diff --git a/core/kamon-core/src/main/scala/kamon/util/DynamicAccess.scala b/core/kamon-core/src/main/scala/kamon/util/DynamicAccess.scala index 2e047d038..33e635352 100644 --- a/core/kamon-core/src/main/scala/kamon/util/DynamicAccess.scala +++ b/core/kamon-core/src/main/scala/kamon/util/DynamicAccess.scala @@ -42,14 +42,16 @@ class DynamicAccess(val classLoader: ClassLoader) { /** * Tries to create an instance of the provided class, passing the provided arguments to the constructor. */ - def createInstanceFor[T: ClassTag](clazz: Class[_], args: immutable.Seq[(Class[_], AnyRef)]): T = try { + def createInstanceFor[T: ClassTag](clazz: Class[_], args: immutable.Seq[(Class[_], AnyRef)]): T = + try { val types = args.map(_._1).toArray val values = args.map(_._2).toArray val constructor = clazz.getDeclaredConstructor(types: _*) constructor.setAccessible(true) val obj = constructor.newInstance(values: _*) val t = implicitly[ClassTag[T]].runtimeClass - if (t.isInstance(obj)) obj.asInstanceOf[T] else throw new ClassCastException(clazz.getName + " is not a subtype of " + t) + if (t.isInstance(obj)) obj.asInstanceOf[T] + else throw new ClassCastException(clazz.getName + " is not a subtype of " + t) } catch { case i: InvocationTargetException if i.getTargetException ne null => throw i.getTargetException } /** @@ -59,4 +61,4 @@ class DynamicAccess(val classLoader: ClassLoader) { def createInstanceFor[T: ClassTag](fqcn: String, args: immutable.Seq[(Class[_], AnyRef)]): T = createInstanceFor(getClassFor(fqcn), args) -} \ No newline at end of file +} diff --git a/core/kamon-core/src/main/scala/kamon/util/EWMA.scala b/core/kamon-core/src/main/scala/kamon/util/EWMA.scala index 165c8812a..87a2a8c1f 100644 --- a/core/kamon-core/src/main/scala/kamon/util/EWMA.scala +++ b/core/kamon-core/src/main/scala/kamon/util/EWMA.scala @@ -31,9 +31,9 @@ import org.slf4j.LoggerFactory * responsive; conversely, if the weighting factor is closer to 1, the moving average will take more iterations to * adapt to new data. */ -class EWMA private(weightingFactor: Double) { - @volatile private var _current = 0D - private val _newDataWeightFactor = 1D - weightingFactor +class EWMA private (weightingFactor: Double) { + @volatile private var _current = 0d + private val _newDataWeightFactor = 1d - weightingFactor private var _count = 0L /** @@ -56,7 +56,7 @@ class EWMA private(weightingFactor: Double) { _count += 1 // Apply bias correction to the current value, if needed - _current = if(_count > 1L) currentValue else currentValue / (1D - Math.pow(weightingFactor, _count)) + _current = if (_count > 1L) currentValue else currentValue / (1d - Math.pow(weightingFactor, _count)) } } @@ -66,7 +66,7 @@ object EWMA { // This roughly means that the moving average is equivalent to the average of the last 10 values. A rough idea of the // number of values represented in the moving average can be calculated via consideredValues = 1 / (1 - factor) - private val _fallbackWeightingFactor = 0.9D + private val _fallbackWeightingFactor = 0.9d /** * Creates a new EWMA instance with a weighting factor of 0.9. @@ -79,10 +79,12 @@ object EWMA { * 0 and 1 (exclusive) then it will be ignored and the default factor of 0.9 will be used. */ def create(weightingFactor: Double): EWMA = - if(weightingFactor > 0D && weightingFactor < 1D) + if (weightingFactor > 0d && weightingFactor < 1d) new EWMA(weightingFactor) else { - _logger.warn(s"Ignoring invalid weighting factor [$weightingFactor] and falling back to [${_fallbackWeightingFactor}]") + _logger.warn( + s"Ignoring invalid weighting factor [$weightingFactor] and falling back to [${_fallbackWeightingFactor}]" + ) new EWMA(_fallbackWeightingFactor) } } diff --git a/core/kamon-core/src/main/scala/kamon/util/EnvironmentTags.scala b/core/kamon-core/src/main/scala/kamon/util/EnvironmentTags.scala index 89fb09fde..eee251e62 100644 --- a/core/kamon-core/src/main/scala/kamon/util/EnvironmentTags.scala +++ b/core/kamon-core/src/main/scala/kamon/util/EnvironmentTags.scala @@ -23,7 +23,6 @@ import kamon.tag.TagSet import scala.collection.JavaConverters._ - /** * Utility class for creating TagSet instances out of Environment instances. When an Environment is turned into tags * it will generate the following pairs: @@ -69,10 +68,10 @@ object EnvironmentTags { * If any of the settings are missing this function will default to include all Environment information. */ def from(environment: Environment, config: Config): TagSet = { - val includeHost = if(config.hasPath("include-host")) config.getBoolean("include-host") else true - val includeService = if(config.hasPath("include-service")) config.getBoolean("include-service") else true - val includeInstance = if(config.hasPath("include-instance")) config.getBoolean("include-instance") else true - val exclude = if(config.hasPath("exclude")) config.getStringList("exclude").asScala.toSet else Set.empty[String] + val includeHost = if (config.hasPath("include-host")) config.getBoolean("include-host") else true + val includeService = if (config.hasPath("include-service")) config.getBoolean("include-service") else true + val includeInstance = if (config.hasPath("include-instance")) config.getBoolean("include-instance") else true + val exclude = if (config.hasPath("exclude")) config.getStringList("exclude").asScala.toSet else Set.empty[String] from(environment, includeService, includeHost, includeInstance, exclude) } @@ -80,23 +79,28 @@ object EnvironmentTags { /** * Turns the information enclosed in the provided Environment instance into a TagSet. */ - def from(environment: Environment, includeService: Boolean, includeHost: Boolean, includeInstance: Boolean, - exclude: Set[String]): TagSet = { + def from( + environment: Environment, + includeService: Boolean, + includeHost: Boolean, + includeInstance: Boolean, + exclude: Set[String] + ): TagSet = { val tagSet = TagSet.builder() - if(includeService) + if (includeService) tagSet.add(TagKeys.Service, environment.service) - if(includeHost) + if (includeHost) tagSet.add(TagKeys.Host, environment.host) - if(includeInstance) + if (includeInstance) tagSet.add(TagKeys.Instance, environment.instance) // We know for sure that all environment tags are treated as Strings environment.tags.iterator(_.toString).foreach { pair => - if(!exclude.contains(pair.key)) tagSet.add(pair.key, pair.value) + if (!exclude.contains(pair.key)) tagSet.add(pair.key, pair.value) } tagSet.build() diff --git a/core/kamon-core/src/main/scala/kamon/util/Filter.scala b/core/kamon-core/src/main/scala/kamon/util/Filter.scala index 6e9a9ccfa..961d6706c 100644 --- a/core/kamon-core/src/main/scala/kamon/util/Filter.scala +++ b/core/kamon-core/src/main/scala/kamon/util/Filter.scala @@ -23,7 +23,6 @@ import com.typesafe.config.Config import scala.collection.JavaConverters.collectionAsScalaIterableConverter - /** * Decides whether a given String satisfy a group of includes and excludes patterns. */ @@ -73,7 +72,7 @@ object Filter { * empty. */ def from(path: String): Filter = - if(Kamon.config().hasPath(path)) + if (Kamon.config().hasPath(path)) from(Kamon.config().getConfig(path)) else Filter.Deny @@ -94,7 +93,7 @@ object Filter { val includes = readFilters(config, "includes") val excludes = readFilters(config, "excludes") - if(includes.isEmpty) + if (includes.isEmpty) Filter.Deny else new Filter.IncludeExclude(includes, excludes) @@ -113,15 +112,15 @@ object Filter { Filter.SingleMatcher(Regex(regexPattern)) private def readFilters(filtersConfig: Config, key: String): Seq[Filter.Matcher] = - if(filtersConfig.hasPath(key)) + if (filtersConfig.hasPath(key)) filtersConfig.getStringList(key).asScala.map(readMatcher).toSeq else Seq.empty private def readMatcher(pattern: String): Filter.Matcher = { - if(pattern.startsWith("regex:")) + if (pattern.startsWith("regex:")) new Filter.Regex(pattern.drop(6)) - else if(pattern.startsWith("glob:")) + else if (pattern.startsWith("glob:")) new Filter.Glob(pattern.drop(5)) else new Filter.Glob(pattern) @@ -206,25 +205,20 @@ object Filter { if (grp1.length == 2) { // it's a *workers are able to process multiple metrics* patternBuilder.append(".*") - } - else { + } else { // it's a * patternBuilder.append("[^/]*") } - } - else if (grp2 != null) { + } else if (grp2 != null) { // match a '?' glob pattern; any non-slash character patternBuilder.append("[^/]") - } - else if (grp3 != null) { + } else if (grp3 != null) { // backslash-escaped value patternBuilder.append(Pattern.quote(grp3.substring(1))) - } - else if (grp4 != null) { + } else if (grp4 != null) { // match any number of / chars patternBuilder.append("/+") - } - else { + } else { // some other string patternBuilder.append(Pattern.quote(matcher.group)) } @@ -233,4 +227,4 @@ object Filter { Pattern.compile(patternBuilder.toString) } } -} \ No newline at end of file +} diff --git a/core/kamon-core/src/main/scala/kamon/util/HexCodec.scala b/core/kamon-core/src/main/scala/kamon/util/HexCodec.scala index acdd907f0..84ce402cf 100644 --- a/core/kamon-core/src/main/scala/kamon/util/HexCodec.scala +++ b/core/kamon-core/src/main/scala/kamon/util/HexCodec.scala @@ -18,6 +18,7 @@ package kamon.util // Extracted from https://github.com/openzipkin/brave/blob/master/brave/src/main/java/brave/internal/HexCodec.java object HexCodec { + /** * Parses a 1 to 32 character lower-hex string with no prefix into an unsigned long, tossing any * bits higher than 64. @@ -82,4 +83,4 @@ object HexCodec { data(pos + 0) = HEX_DIGITS((b >> 4) & 0xf) data(pos + 1) = HEX_DIGITS(b & 0xf) } -} \ No newline at end of file +} diff --git a/core/kamon-core/src/main/scala/kamon/util/UnitConverter.scala b/core/kamon-core/src/main/scala/kamon/util/UnitConverter.scala index 0fe31b2ce..61f8885ea 100644 --- a/core/kamon-core/src/main/scala/kamon/util/UnitConverter.scala +++ b/core/kamon-core/src/main/scala/kamon/util/UnitConverter.scala @@ -24,16 +24,20 @@ import kamon.metric.{Distribution, DynamicRange, MeasurementUnit} * keep fixed preferences regarding what time and information units to expect on the output and apply those conversion * when possible. */ -class UnitConverter(targetTimeUnit: MeasurementUnit, targetInformationUnit: MeasurementUnit, dynamicRange: DynamicRange) { +class UnitConverter( + targetTimeUnit: MeasurementUnit, + targetInformationUnit: MeasurementUnit, + dynamicRange: DynamicRange +) { /** * Tries to convert a value from its unit to the appropriate time/information unit set when creating this * UnitConverter. If the value unit's dimension is not time or information then values will be returned unchanged. */ def convertValue(value: Double, unit: MeasurementUnit): Double = - if(unit.dimension == Dimension.Time) + if (unit.dimension == Dimension.Time) MeasurementUnit.convert(value, unit, targetTimeUnit) - else if(unit.dimension == Dimension.Information) + else if (unit.dimension == Dimension.Information) MeasurementUnit.convert(value, unit, targetInformationUnit) else value @@ -44,9 +48,9 @@ class UnitConverter(targetTimeUnit: MeasurementUnit, targetInformationUnit: Meas * be converted to a different dynamic range, if necessary. */ def convertDistribution(distribution: Distribution, unit: MeasurementUnit): Distribution = - if(unit.dimension == Dimension.Time) + if (unit.dimension == Dimension.Time) Distribution.convert(distribution, unit, targetTimeUnit, dynamicRange) - else if(unit.dimension == Dimension.Information) + else if (unit.dimension == Dimension.Information) Distribution.convert(distribution, unit, targetInformationUnit, dynamicRange) else Distribution.convert(distribution, unit, unit, dynamicRange) diff --git a/core/kamon-status-page/src/main/scala/kamon/status/page/JsonMarshalling.scala b/core/kamon-status-page/src/main/scala/kamon/status/page/JsonMarshalling.scala index ce02dfa0f..6a1088cc0 100644 --- a/core/kamon-status-page/src/main/scala/kamon/status/page/JsonMarshalling.scala +++ b/core/kamon-status-page/src/main/scala/kamon/status/page/JsonMarshalling.scala @@ -26,7 +26,6 @@ import kamon.tag.{Tag, TagSet} import scala.compat.Platform.EOL - trait JsonMarshalling[T] { /** @@ -42,10 +41,10 @@ object JsonMarshalling { override def toJson(instance: Status.ModuleRegistry, builder: JavaStringBuilder): Unit = { def moduleKindString(moduleKind: Module.Kind): String = moduleKind match { case Module.Kind.CombinedReporter => "combined" - case Module.Kind.MetricsReporter => "metric" - case Module.Kind.SpansReporter => "span" - case Module.Kind.ScheduledAction => "scheduled" - case Module.Kind.Unknown => "unknown" + case Module.Kind.MetricsReporter => "metric" + case Module.Kind.SpansReporter => "span" + case Module.Kind.ScheduledAction => "scheduled" + case Module.Kind.Unknown => "unknown" } val array = JsonWriter.on(builder) @@ -72,8 +71,8 @@ object JsonMarshalling { override def toJson(instance: Status.Settings, builder: JavaStringBuilder): Unit = { val baseConfigJson = JsonWriter.on(builder) .`object`() - .value("version", instance.version) - .value("config", instance.config.root().render(ConfigRenderOptions.concise())) + .value("version", instance.version) + .value("config", instance.config.root().render(ConfigRenderOptions.concise())) baseConfigJson.`object`("environment") .value("service", instance.environment.service) @@ -97,17 +96,17 @@ object JsonMarshalling { override def toJson(instance: Status.MetricRegistry, builder: JavaStringBuilder): Unit = { val metricsObject = JsonWriter.on(builder) .`object` - .array("metrics") + .array("metrics") instance.metrics.foreach(metric => { metricsObject .`object`() - .value("name", metric.name) - .value("description", metric.description) - .value("type", metric.instrumentType.name) - .value("unitDimension", metric.unit.dimension.name) - .value("unitMagnitude", metric.unit.magnitude.name) - .value("instrumentType", metric.instrumentType.name) + .value("name", metric.name) + .value("description", metric.description) + .value("type", metric.instrumentType.name) + .value("unitDimension", metric.unit.dimension.name) + .value("unitMagnitude", metric.unit.magnitude.name) + .value("instrumentType", metric.instrumentType.name) val instrumentsArray = metricsObject.array("instruments") metric.instruments.foreach(i => tagSetToJson(i.tags, instrumentsArray)) @@ -134,8 +133,8 @@ object JsonMarshalling { override def toJson(instance: Status.Instrumentation, builder: JavaStringBuilder): Unit = { val instrumentationObject = JsonWriter.on(builder) .`object`() - .value("present", instance.present) - .`object`("modules") + .value("present", instance.present) + .`object`("modules") instance.modules.foreach { module => instrumentationObject.`object`(module.path) @@ -167,4 +166,4 @@ object JsonMarshalling { .done() } } -} \ No newline at end of file +} diff --git a/core/kamon-status-page/src/main/scala/kamon/status/page/StatusPage.scala b/core/kamon-status-page/src/main/scala/kamon/status/page/StatusPage.scala index 6c23f9192..14c3c1196 100644 --- a/core/kamon-status-page/src/main/scala/kamon/status/page/StatusPage.scala +++ b/core/kamon-status-page/src/main/scala/kamon/status/page/StatusPage.scala @@ -41,7 +41,6 @@ class StatusPage(configPath: String) extends Module { override def reconfigure(newConfig: Config): Unit = init(newConfig.getConfig(configPath)) - private def init(config: Config): Unit = synchronized { val hostname = config.getString("listen.hostname") val port = config.getInt("listen.port") @@ -55,14 +54,19 @@ class StatusPage(configPath: String) extends Module { // If the configuration has changed we will stop the previous version // and start a new one with the new hostname/port. - if(existentServer.getHostname != hostname || existentServer.getListeningPort != port) { + if (existentServer.getHostname != hostname || existentServer.getListeningPort != port) { stopServer() startServer(hostname, port, ClassLoading.classLoader(), retryOnRandomPort) } }) } - private def startServer(hostname: String, port: Int, resourceLoader: ClassLoader, retryOnRandomPort: Boolean): Unit = { + private def startServer( + hostname: String, + port: Int, + resourceLoader: ClassLoader, + retryOnRandomPort: Boolean + ): Unit = { Try { val server = new StatusPageServer(hostname, port, resourceLoader, Kamon.status()) server.start() diff --git a/core/kamon-status-page/src/main/scala/kamon/status/page/StatusPageServer.scala b/core/kamon-status-page/src/main/scala/kamon/status/page/StatusPageServer.scala index 3ad7d585e..6deac6ee1 100644 --- a/core/kamon-status-page/src/main/scala/kamon/status/page/StatusPageServer.scala +++ b/core/kamon-status-page/src/main/scala/kamon/status/page/StatusPageServer.scala @@ -37,17 +37,17 @@ class StatusPageServer(hostname: String, port: Int, resourceLoader: ClassLoader, private val ResourceExtensionRegex = ".*\\.([a-zA-Z0-9]*)".r override def serve(session: NanoHTTPD.IHTTPSession): NanoHTTPD.Response = { - if(session.getMethod() == NanoHTTPD.Method.GET) { + if (session.getMethod() == NanoHTTPD.Method.GET) { try { if (session.getUri().startsWith("/status")) { // Serve the current status data on Json. session.getUri() match { - case "/status/settings" => json(status.settings()) - case "/status/modules" => json(status.moduleRegistry()) - case "/status/metrics" => json(status.metricRegistry()) + case "/status/settings" => json(status.settings()) + case "/status/modules" => json(status.moduleRegistry()) + case "/status/metrics" => json(status.metricRegistry()) case "/status/instrumentation" => json(status.instrumentation()) - case _ => NotFound + case _ => NotFound } } else { @@ -74,13 +74,13 @@ class StatusPageServer(hostname: String, port: Int, resourceLoader: ClassLoader, private def mimeType(resource: String): String = { val ResourceExtensionRegex(resourceExtension) = resource resourceExtension match { - case "css" => "text/css" - case "js" => "application/javascript" - case "ico" => "image/x-icon" - case "svg" => "image/svg+xml" - case "html" => "text/html" - case "woff2" => "font/woff2" - case _ => "text/plain" + case "css" => "text/css" + case "js" => "application/javascript" + case "ico" => "image/x-icon" + case "svg" => "image/svg+xml" + case "html" => "text/html" + case "woff2" => "font/woff2" + case _ => "text/plain" } } @@ -122,7 +122,6 @@ class StatusPageServer(hostname: String, port: Int, resourceLoader: ClassLoader, NotAllowed.closeConnection(true) NotFound.closeConnection(true) - /** * AsyncRunner that uses a thread pool for handling requests rather than spawning a new thread for each request (as * the default runner does). @@ -141,4 +140,4 @@ class StatusPageServer(hostname: String, port: Int, resourceLoader: ClassLoader, _openRequests.add(clientHandler) } } -} \ No newline at end of file +} diff --git a/core/kamon-testkit/src/main/scala/kamon/testkit/InstrumentInspection.scala b/core/kamon-testkit/src/main/scala/kamon/testkit/InstrumentInspection.scala index 2013c040f..77c43f9cb 100644 --- a/core/kamon-testkit/src/main/scala/kamon/testkit/InstrumentInspection.scala +++ b/core/kamon-testkit/src/main/scala/kamon/testkit/InstrumentInspection.scala @@ -42,10 +42,12 @@ object InstrumentInspection { instrument.asInstanceOf[Instrument.Snapshotting[Distribution]].snapshot(resetState = true) /** Retrieves the current value of an instruments */ - def distribution(instrument: Instrument[_, Metric.Settings.ForDistributionInstrument], resetState: Boolean): Distribution = + def distribution( + instrument: Instrument[_, Metric.Settings.ForDistributionInstrument], + resetState: Boolean + ): Distribution = instrument.asInstanceOf[Instrument.Snapshotting[Distribution]].snapshot(resetState) - /** * Exposes an implicitly available syntax to extract values and distribution from instruments. */ @@ -66,27 +68,30 @@ object InstrumentInspection { } /** Retrieves the current value of a Counter instrument */ - implicit def counterInstrumentInspection(instrument: Instrument[Counter, Metric.Settings.ForValueInstrument]): RichCounterInstrument = - new RichCounterInstrument { + implicit def counterInstrumentInspection(instrument: Instrument[Counter, Metric.Settings.ForValueInstrument]) + : RichCounterInstrument = + new RichCounterInstrument { - def value(): Long = - InstrumentInspection.longValue(instrument) + def value(): Long = + InstrumentInspection.longValue(instrument) - def value(resetState: Boolean): Long = - InstrumentInspection.longValue(instrument, resetState) - } + def value(resetState: Boolean): Long = + InstrumentInspection.longValue(instrument, resetState) + } /** Retrieves the current value of a Gauge instrument */ - implicit def gaugeInstrumentInspection(instrument: Instrument[Gauge, Metric.Settings.ForValueInstrument]): RichGaugeInstrument = - new RichGaugeInstrument { + implicit def gaugeInstrumentInspection(instrument: Instrument[Gauge, Metric.Settings.ForValueInstrument]) + : RichGaugeInstrument = + new RichGaugeInstrument { - def value(): Double = - InstrumentInspection.doubleValue(instrument) - } + def value(): Double = + InstrumentInspection.doubleValue(instrument) + } /** Retrieves the current distribution of a histogram, timer or range sampler instrument */ - implicit def distributionInstrumentInspection[T <: Instrument[T, Metric.Settings.ForDistributionInstrument]] - (instrument: T): RichDistributionInstrument = new RichDistributionInstrument { + implicit def distributionInstrumentInspection[T <: Instrument[T, Metric.Settings.ForDistributionInstrument]]( + instrument: T + ): RichDistributionInstrument = new RichDistributionInstrument { def distribution(): Distribution = InstrumentInspection.distribution(instrument) @@ -97,4 +102,4 @@ object InstrumentInspection { } object Syntax extends Syntax -} \ No newline at end of file +} diff --git a/core/kamon-testkit/src/main/scala/kamon/testkit/MetricInspection.scala b/core/kamon-testkit/src/main/scala/kamon/testkit/MetricInspection.scala index 3849bd990..856506c13 100644 --- a/core/kamon-testkit/src/main/scala/kamon/testkit/MetricInspection.scala +++ b/core/kamon-testkit/src/main/scala/kamon/testkit/MetricInspection.scala @@ -23,7 +23,6 @@ import kamon.tag.Lookups._ import scala.collection.concurrent.TrieMap - /** * Utility functions to extract tags and instrument information from metrics. These utilities are only meant to be used * for testing purposes. @@ -33,7 +32,10 @@ object MetricInspection { /** * Returns all values for a given tag across all instruments of the inspected metric. */ - def tagValues[Inst <: Instrument[Inst, Sett], Sett <: Metric.Settings](metric: Metric[Inst, Sett], key: String): Seq[String] = { + def tagValues[Inst <: Instrument[Inst, Sett], Sett <: Metric.Settings]( + metric: Metric[Inst, Sett], + key: String + ): Seq[String] = { instrumentsMap(metric).keys .map(t => t.get(coerce(key, ""))) .filter(_.nonEmpty) @@ -46,7 +48,8 @@ object MetricInspection { /** * Returns all instruments currently registered for the inspected metric. */ - def instruments[Inst <: Instrument[Inst, Sett], Sett <: Metric.Settings](metric: Metric[Inst, Sett]): Map[TagSet, Inst] = { + def instruments[Inst <: Instrument[Inst, Sett], Sett <: Metric.Settings](metric: Metric[Inst, Sett]) + : Map[TagSet, Inst] = { instrumentsMap(metric) .mapValues(extractInstrumentFromEntry[Inst]) .toMap @@ -55,7 +58,10 @@ object MetricInspection { /** * Returns all instruments that contain at least the provided tags for the inspected metric. */ - def instruments[Inst <: Instrument[Inst, Sett], Sett <: Metric.Settings](metric: Metric[Inst, Sett], tags: TagSet): Map[TagSet, Inst] = { + def instruments[Inst <: Instrument[Inst, Sett], Sett <: Metric.Settings]( + metric: Metric[Inst, Sett], + tags: TagSet + ): Map[TagSet, Inst] = { def hasAllRequestedTags(instrumentTags: TagSet): Boolean = { val instrumentPairs = instrumentTags.iterator().map(t => (t.key -> Tag.unwrapValue(t))).toMap tags.iterator().forall(t => instrumentPairs.get(t.key).exists(sv => sv == Tag.unwrapValue(t))) @@ -67,15 +73,18 @@ object MetricInspection { .toMap } - - private def instrumentsMap[Inst <: Instrument[Inst, Sett], Sett <: Metric.Settings](metric: Metric[Inst, Sett]): TrieMap[TagSet, Any] = { + private def instrumentsMap[Inst <: Instrument[Inst, Sett], Sett <: Metric.Settings](metric: Metric[Inst, Sett]) + : TrieMap[TagSet, Any] = { Reflection.getFieldFromClass[TrieMap[TagSet, Any]](metric, "kamon.metric.Metric$BaseMetric", "_instruments") .filter { case (_, entry) => - !Reflection.getFieldFromClass[Boolean](entry, "kamon.metric.Metric$BaseMetric$InstrumentEntry", "removeOnNextSnapshot") + !Reflection.getFieldFromClass[Boolean]( + entry, + "kamon.metric.Metric$BaseMetric$InstrumentEntry", + "removeOnNextSnapshot" + ) } } - /** * Exposes an implicitly available syntax for inspecting tags and instruments from a metric. */ @@ -87,19 +96,22 @@ object MetricInspection { def instruments(tags: TagSet): Map[TagSet, Inst] } - implicit def metricInspectionSyntax[Inst <: Instrument[Inst, Sett], Sett <: Metric.Settings](metric: Metric[Inst, Sett]): RichMetric[Inst, Sett] = - new RichMetric[Inst, Sett] { + implicit def metricInspectionSyntax[Inst <: Instrument[Inst, Sett], Sett <: Metric.Settings](metric: Metric[ + Inst, + Sett + ]): RichMetric[Inst, Sett] = + new RichMetric[Inst, Sett] { - def tagValues(key: String): Seq[String] = - MetricInspection.tagValues(metric, key) + def tagValues(key: String): Seq[String] = + MetricInspection.tagValues(metric, key) - def instruments(): Map[TagSet, Inst] = - MetricInspection.instruments(metric) + def instruments(): Map[TagSet, Inst] = + MetricInspection.instruments(metric) - def instruments(tags: TagSet): Map[TagSet, Inst] = - MetricInspection.instruments(metric, tags) - } + def instruments(tags: TagSet): Map[TagSet, Inst] = + MetricInspection.instruments(metric, tags) + } } object Syntax extends Syntax -} \ No newline at end of file +} diff --git a/core/kamon-testkit/src/main/scala/kamon/testkit/MetricSnapshotBuilder.scala b/core/kamon-testkit/src/main/scala/kamon/testkit/MetricSnapshotBuilder.scala index 4441967ad..92bbfdf58 100644 --- a/core/kamon-testkit/src/main/scala/kamon/testkit/MetricSnapshotBuilder.scala +++ b/core/kamon-testkit/src/main/scala/kamon/testkit/MetricSnapshotBuilder.scala @@ -43,7 +43,13 @@ object MetricSnapshotBuilder { /** * Returns a metric snapshot containing a single instrument with a snapshot containing the provided attributes. */ - def counter(name: String, description: String, tags: TagSet, unit: MeasurementUnit, value: Long): MetricSnapshot.Values[Long] = { + def counter( + name: String, + description: String, + tags: TagSet, + unit: MeasurementUnit, + value: Long + ): MetricSnapshot.Values[Long] = { MetricSnapshot( name, description, @@ -67,7 +73,13 @@ object MetricSnapshotBuilder { /** * Returns a metric snapshot containing a single instrument with a snapshot containing the provided attributes. */ - def gauge(name: String, description: String, tags: TagSet, unit: MeasurementUnit, value: Double): MetricSnapshot.Values[Double] = { + def gauge( + name: String, + description: String, + tags: TagSet, + unit: MeasurementUnit, + value: Double + ): MetricSnapshot.Values[Double] = { MetricSnapshot( name, description, @@ -94,7 +106,12 @@ object MetricSnapshotBuilder { * Returns a metric snapshot containing a single instrument with a distribution snapshot containing the provided * attributes and values. */ - def histogram(name: String, description: String, tags: TagSet, unit: MeasurementUnit)(values: Long*): MetricSnapshot.Distributions = { + def histogram( + name: String, + description: String, + tags: TagSet, + unit: MeasurementUnit + )(values: Long*): MetricSnapshot.Distributions = { val localHistogram = Histogram.Local.get(DynamicRange.Default) localHistogram.reset() @@ -108,5 +125,4 @@ object MetricSnapshotBuilder { ) } - } diff --git a/core/kamon-testkit/src/main/scala/kamon/testkit/Reconfigure.scala b/core/kamon-testkit/src/main/scala/kamon/testkit/Reconfigure.scala index 6b6404160..ea9eb3bda 100644 --- a/core/kamon-testkit/src/main/scala/kamon/testkit/Reconfigure.scala +++ b/core/kamon-testkit/src/main/scala/kamon/testkit/Reconfigure.scala @@ -27,63 +27,54 @@ trait Reconfigure { def enableFastMetricFlushing(): Unit = applyConfig("kamon.metric.tick-interval = 1 millisecond") - /** * Makes Kamon flush spans to reporters every millisecond */ def enableFastSpanFlushing(): Unit = applyConfig("kamon.trace.tick-interval = 1 millisecond") - /** * Makes Kamon sample all new traces */ def sampleAlways(): Unit = applyConfig("kamon.trace.sampler = always") - /** * Makes Kamon never sample a new trace */ def sampleNever(): Unit = applyConfig("kamon.trace.sampler = never") - /** * Enables scoping of Span metrics to their parent operation */ def enableSpanMetricScoping(): Unit = applyConfig("kamon.trace.span-metric-tags.parent-operation = yes") - /** * Disables scoping of Span metrics to their parent operation */ def disableSpanMetricScoping(): Unit = applyConfig("kamon.trace.span-metric-tags.parent-operation = no") - /** * Enables using the same Span identifier as their remote parent on server operations. */ def enableJoiningRemoteParentWithSameId(): Unit = applyConfig("kamon.trace.join-remote-parents-with-same-span-id = yes") - /** * Disables using the same Span identifier as their remote parent on server operations. */ def disableJoiningRemoteParentWithSameId(): Unit = applyConfig("kamon.trace.join-remote-parents-with-same-span-id = no") - /** * Parses the provided configuration and reconfigures Kamon with it */ def applyConfig(configString: String): Unit = Kamon.reconfigure(ConfigFactory.parseString(configString).withFallback(Kamon.config())) - /** * Resets Kamon's configuration what would be loaded by default. */ diff --git a/core/kamon-testkit/src/main/scala/kamon/testkit/Reflection.scala b/core/kamon-testkit/src/main/scala/kamon/testkit/Reflection.scala index 7704c2030..b35d79c9f 100644 --- a/core/kamon-testkit/src/main/scala/kamon/testkit/Reflection.scala +++ b/core/kamon-testkit/src/main/scala/kamon/testkit/Reflection.scala @@ -41,7 +41,9 @@ object Reflection { /** * Invokes a method on the target object using reflection. */ - def invoke[T, R](target: Any, fieldName: String, parameters: (Class[_], AnyRef)*)(implicit classTag: ClassTag[T]): R = { + def invoke[T, R](target: Any, fieldName: String, parameters: (Class[_], AnyRef)*)(implicit + classTag: ClassTag[T] + ): R = { val parameterClasses = parameters.map(_._1) val parameterInstances = parameters.map(_._2) val method = classTag.runtimeClass.getDeclaredMethod(fieldName, parameterClasses: _*) diff --git a/core/kamon-testkit/src/main/scala/kamon/testkit/SpanInspection.scala b/core/kamon-testkit/src/main/scala/kamon/testkit/SpanInspection.scala index ed53f36e2..04b22e81f 100644 --- a/core/kamon-testkit/src/main/scala/kamon/testkit/SpanInspection.scala +++ b/core/kamon-testkit/src/main/scala/kamon/testkit/SpanInspection.scala @@ -22,7 +22,6 @@ import java.time.Instant import kamon.tag.TagSet import kamon.trace.Span - /** * Utility functions to extract information that is not exposed on the Span interface. */ @@ -32,42 +31,38 @@ trait SpanInspection { def inspect(span: Span): Inspector = new Inspector(span) - class Inspector(span: Span) { /** * Returns a TagSet with all Span tags added on the Span. */ def spanTags(): TagSet = - if(span.isInstanceOf[Span.Local]) + if (span.isInstanceOf[Span.Local]) Reflection.getField[Span.Local, TagSet.Builder](span.asInstanceOf[Span.Local], "_spanTags").build() else TagSet.Empty - /** * Returns a TagSet with all Span metric tags added to the Span and the additional tags that are added by default * like the "error", "operation" and possibly "parentOperation" tags. */ def metricTags(): TagSet = - if(span.isInstanceOf[Span.Local]) + if (span.isInstanceOf[Span.Local]) Reflection.invoke[Span.Local, TagSet](span.asInstanceOf[Span.Local], "createMetricTags") else TagSet.Empty - /** * Returns a combination of all tags (span and metric tags) on the Span. */ def tags(): TagSet = spanTags() withTags metricTags() - /** * Returns all marks on the Span. */ def marks(): Seq[Span.Mark] = - if(span.isInstanceOf[Span.Local]) + if (span.isInstanceOf[Span.Local]) Reflection.getField[Span.Local, Seq[Span.Mark]](span.asInstanceOf[Span.Local], "_marks") else Seq.empty @@ -76,36 +71,37 @@ trait SpanInspection { * Returns true if the Span has been marked as failed. */ def isFailed(): Boolean = - if(span.isInstanceOf[Span.Local]) + if (span.isInstanceOf[Span.Local]) Reflection.getField[Span.Local, Boolean](span.asInstanceOf[Span.Local], "_hasError") else false - /** * Returns true if the Span is set to track metrics once it is finished. */ def isTrackingMetrics(): Boolean = - if(span.isInstanceOf[Span.Local]) + if (span.isInstanceOf[Span.Local]) Reflection.getField[Span.Local, Boolean](span.asInstanceOf[Span.Local], "_trackMetrics") else false - /** * Returns the Span.Finished instance that would be sent to the SpanReporters if the Span's trace is sampled. */ def toFinished(): Span.Finished = toFinished(Kamon.clock().instant()) - /** * Returns the Span.Finished instance that would be sent to the SpanReporters if the Span's trace is sampled. */ def toFinished(at: Instant): Span.Finished = - if(span.isInstanceOf[Span.Local]) - Reflection.invoke[Span.Local, Span.Finished](span.asInstanceOf[Span.Local], "toFinishedSpan", - (classOf[Instant], at), (classOf[TagSet], metricTags())) + if (span.isInstanceOf[Span.Local]) + Reflection.invoke[Span.Local, Span.Finished]( + span.asInstanceOf[Span.Local], + "toFinishedSpan", + (classOf[Instant], at), + (classOf[TagSet], metricTags()) + ) else sys.error("Cannot finish an Empty/Remote Span") @@ -158,4 +154,4 @@ trait SpanInspection { } } -object SpanInspection extends SpanInspection \ No newline at end of file +object SpanInspection extends SpanInspection diff --git a/core/kamon-testkit/src/test/scala/kamon/testkit/MetricInspectionSpec.scala b/core/kamon-testkit/src/test/scala/kamon/testkit/MetricInspectionSpec.scala index 68ac4710e..8536902e8 100644 --- a/core/kamon-testkit/src/test/scala/kamon/testkit/MetricInspectionSpec.scala +++ b/core/kamon-testkit/src/test/scala/kamon/testkit/MetricInspectionSpec.scala @@ -15,7 +15,7 @@ class MetricInspectionSpec extends AnyWordSpec with Matchers with MetricInspecti metric.withTags(ts1).increment(1) metric.withTags(ts2).increment(2) - metric.instruments().values.map(_.tags) should contain allOf(ts1, ts2) + metric.instruments().values.map(_.tags) should contain allOf (ts1, ts2) metric.instruments(ts1).keys.headOption shouldBe Some(ts1) } @@ -27,7 +27,7 @@ class MetricInspectionSpec extends AnyWordSpec with Matchers with MetricInspecti metric.withTag("season", "autumn").increment() metric.tagValues("unknown") shouldBe empty - metric.tagValues("season") should contain allOf( + metric.tagValues("season") should contain allOf ( "summer", "winter", "spring", @@ -37,5 +37,3 @@ class MetricInspectionSpec extends AnyWordSpec with Matchers with MetricInspecti } } - - diff --git a/instrumentation/kamon-akka-grpc/src/main/scala/kamon/instrumentation/akka/grpc/AkkaGrpcServerInstrumentation.scala b/instrumentation/kamon-akka-grpc/src/main/scala/kamon/instrumentation/akka/grpc/AkkaGrpcServerInstrumentation.scala index a89f46484..f57d9bf7c 100644 --- a/instrumentation/kamon-akka-grpc/src/main/scala/kamon/instrumentation/akka/grpc/AkkaGrpcServerInstrumentation.scala +++ b/instrumentation/kamon-akka-grpc/src/main/scala/kamon/instrumentation/akka/grpc/AkkaGrpcServerInstrumentation.scala @@ -38,7 +38,6 @@ class AkkaGrpcServerInstrumentation extends InstrumentationBuilder { onType("akka.grpc.internal.TelemetrySpi") .advise(method("onRequest"), classOf[AkkaGRPCServerRequestHandler]) - onType("akka.grpc.javadsl.GrpcMarshalling") .advise(method("unmarshal"), classOf[AkkaGRPCUnmarshallingContextPropagation]) } diff --git a/instrumentation/kamon-akka-grpc/src/test/scala/kamon/instrumentation/akka/grpc/AkkaGrpcTracingSpec.scala b/instrumentation/kamon-akka-grpc/src/test/scala/kamon/instrumentation/akka/grpc/AkkaGrpcTracingSpec.scala index 877fe387d..1ef0f88e8 100644 --- a/instrumentation/kamon-akka-grpc/src/test/scala/kamon/instrumentation/akka/grpc/AkkaGrpcTracingSpec.scala +++ b/instrumentation/kamon-akka-grpc/src/test/scala/kamon/instrumentation/akka/grpc/AkkaGrpcTracingSpec.scala @@ -40,7 +40,6 @@ class AkkaGrpcTracingSpec extends AnyWordSpec with InitAndStopKamonAfterAll with .newServerAt("127.0.0.1", 8598) .bind(greeterService) - val client = GreeterServiceClient(GrpcClientSettings.connectToServiceAt("127.0.0.1", 8598).withTls(false)) "the Akka gRPC instrumentation" should { diff --git a/instrumentation/kamon-akka-grpc/src/test/scala/kamon/instrumentation/akka/grpc/GreeterServiceImpl.scala b/instrumentation/kamon-akka-grpc/src/test/scala/kamon/instrumentation/akka/grpc/GreeterServiceImpl.scala index c29d58d14..30bfd7de4 100644 --- a/instrumentation/kamon-akka-grpc/src/test/scala/kamon/instrumentation/akka/grpc/GreeterServiceImpl.scala +++ b/instrumentation/kamon-akka-grpc/src/test/scala/kamon/instrumentation/akka/grpc/GreeterServiceImpl.scala @@ -22,7 +22,6 @@ import akka.stream.Materializer import akka.stream.scaladsl.Sink import akka.stream.scaladsl.Source - class GreeterServiceImpl(implicit mat: Materializer) extends GreeterService { import mat.executionContext diff --git a/instrumentation/kamon-akka-http/src/main/scala-2.12/kamon/instrumentation/akka/http/AkkaHttpServerInstrumentation.scala b/instrumentation/kamon-akka-http/src/main/scala-2.12/kamon/instrumentation/akka/http/AkkaHttpServerInstrumentation.scala index 2afa0b770..2a48e71fb 100644 --- a/instrumentation/kamon-akka-http/src/main/scala-2.12/kamon/instrumentation/akka/http/AkkaHttpServerInstrumentation.scala +++ b/instrumentation/kamon-akka-http/src/main/scala-2.12/kamon/instrumentation/akka/http/AkkaHttpServerInstrumentation.scala @@ -45,7 +45,6 @@ import kanela.agent.libs.net.bytebuddy.matcher.ElementMatchers.isPublic import scala.collection.immutable - class AkkaHttpServerInstrumentation extends InstrumentationBuilder { /** @@ -87,7 +86,10 @@ class AkkaHttpServerInstrumentation extends InstrumentationBuilder { onType("akka.http.scaladsl.server.directives.FutureDirectives") .intercept(method("onComplete"), classOf[ResolveOperationNameOnRouteInterceptor]) - onTypes("akka.http.scaladsl.server.directives.OnSuccessMagnet$", "akka.http.scaladsl.server.directives.CompleteOrRecoverWithMagnet$") + onTypes( + "akka.http.scaladsl.server.directives.OnSuccessMagnet$", + "akka.http.scaladsl.server.directives.CompleteOrRecoverWithMagnet$" + ) .intercept(method("apply"), classOf[ResolveOperationNameOnRouteInterceptor]) onType("akka.http.scaladsl.server.directives.RouteDirectives") @@ -102,7 +104,6 @@ class AkkaHttpServerInstrumentation extends InstrumentationBuilder { onType("akka.http.scaladsl.Http2Ext") .advise(method("bindAndHandleAsync") and isPublic(), classOf[Http2ExtBindAndHandleAdvice]) - /** * Support for HTTP/1 and HTTP/2 at the same time. * @@ -123,12 +124,13 @@ trait HasMatchingContext { object HasMatchingContext { - case class PathMatchingContext ( + case class PathMatchingContext( fullPath: String, matched: Matched[_] ) - class Mixin(var matchingContext: Seq[PathMatchingContext], var defaultOperationName: String) extends HasMatchingContext { + class Mixin(var matchingContext: Seq[PathMatchingContext], var defaultOperationName: String) + extends HasMatchingContext { override def setMatchingContext(matchingContext: Seq[PathMatchingContext]): Unit = this.matchingContext = matchingContext @@ -162,7 +164,9 @@ object ResolveOperationNameOnRouteInterceptor { def complete[T](status: StatusCode, v: => T)(implicit m: ToEntityMarshaller[T]): StandardRoute = StandardRoute(resolveOperationName(_).complete((status, v))) - def complete[T](status: StatusCode, headers: immutable.Seq[HttpHeader], v: => T)(implicit m: ToEntityMarshaller[T]): StandardRoute = + def complete[T](status: StatusCode, headers: immutable.Seq[HttpHeader], v: => T)(implicit + m: ToEntityMarshaller[T] + ): StandardRoute = complete((status, headers, v)) def redirect(uri: Uri, redirectionType: Redirection): StandardRoute = @@ -211,18 +215,18 @@ object ResolveOperationNameOnRouteInterceptor { Kamon.currentContext().get(LastAutomaticOperationNameEdit.Key).foreach(lastEdit => { val currentSpan = Kamon.currentSpan() - if(lastEdit.allowAutomaticChanges) { - if(currentSpan.operationName() == lastEdit.operationName) { - val allMatches = requestContext.asInstanceOf[HasMatchingContext].matchingContext.reverse.map(singleMatch) - val operationName = allMatches.mkString("") + if (lastEdit.allowAutomaticChanges) { + if (currentSpan.operationName() == lastEdit.operationName) { + val allMatches = requestContext.asInstanceOf[HasMatchingContext].matchingContext.reverse.map(singleMatch) + val operationName = allMatches.mkString("") - if(operationName.nonEmpty) { + if (operationName.nonEmpty) { currentSpan - .name(operationName) - .takeSamplingDecision() + .name(operationName) + .takeSamplingDecision() - lastEdit.operationName = operationName - } + lastEdit.operationName = operationName + } } else { lastEdit.allowAutomaticChanges = false } @@ -240,7 +244,7 @@ object ResolveOperationNameOnRouteInterceptor { val consumedSegment = matching.fullPath.substring(0, consumedCount) matching.matched.extractions match { - case () => //string segment matched + case () => // string segment matched consumedSegment case tuple: Product => val values = tuple.productIterator.toList map { @@ -286,7 +290,9 @@ object RequestContextCopyInterceptor { @RuntimeType def copy(@This context: RequestContext, @SuperCall copyCall: Callable[RequestContext]): RequestContext = { val copiedRequestContext = copyCall.call() - copiedRequestContext.asInstanceOf[HasMatchingContext].setMatchingContext(context.asInstanceOf[HasMatchingContext].matchingContext) + copiedRequestContext.asInstanceOf[HasMatchingContext].setMatchingContext( + context.asInstanceOf[HasMatchingContext].matchingContext + ) copiedRequestContext } } @@ -313,8 +319,7 @@ object PathDirectivesRawPathPrefixInterceptor { } flatMap { case (ctx, Matched(rest, values)) => tprovide(values) & mapRequestContext(_ withUnmatchedPath rest) & mapRouteResult { routeResult => - - if(routeResult.isInstanceOf[Rejected]) + if (routeResult.isInstanceOf[Rejected]) ctx.asInstanceOf[HasMatchingContext].popOneMatchingContext() routeResult @@ -325,7 +330,6 @@ object PathDirectivesRawPathPrefixInterceptor { } } - object Http2BlueprintInterceptor { case class HandlerWithEndpoint(interface: String, port: Int, handler: HttpRequest => Future[HttpResponse]) @@ -335,8 +339,10 @@ object Http2BlueprintInterceptor { } @RuntimeType - def handleWithStreamIdHeader(@Argument(1) handler: HttpRequest => Future[HttpResponse], - @SuperCall zuper: Callable[Flow[HttpRequest, HttpResponse, NotUsed]]): Flow[HttpRequest, HttpResponse, NotUsed] = { + def handleWithStreamIdHeader( + @Argument(1) handler: HttpRequest => Future[HttpResponse], + @SuperCall zuper: Callable[Flow[HttpRequest, HttpResponse, NotUsed]] + ): Flow[HttpRequest, HttpResponse, NotUsed] = { handler match { case HandlerWithEndpoint(interface, port, _) => diff --git a/instrumentation/kamon-akka-http/src/main/scala/kamon/instrumentation/akka/http/AkkaHttpClientInstrumentation.scala b/instrumentation/kamon-akka-http/src/main/scala/kamon/instrumentation/akka/http/AkkaHttpClientInstrumentation.scala index e4891bf0f..9f84b2106 100644 --- a/instrumentation/kamon-akka-http/src/main/scala/kamon/instrumentation/akka/http/AkkaHttpClientInstrumentation.scala +++ b/instrumentation/kamon-akka-http/src/main/scala/kamon/instrumentation/akka/http/AkkaHttpClientInstrumentation.scala @@ -45,18 +45,21 @@ class AkkaHttpClientInstrumentation extends InstrumentationBuilder with VersionF object AkkaHttpClientInstrumentation { - @volatile var httpClientInstrumentation: HttpClientInstrumentation = rebuildHttpClientInstrumentation + @volatile var httpClientInstrumentation: HttpClientInstrumentation = rebuildHttpClientInstrumentation - private[http] def rebuildHttpClientInstrumentation(): HttpClientInstrumentation = { - val httpClientConfig = Kamon.config().getConfig("kamon.instrumentation.akka.http.client") - httpClientInstrumentation = HttpClientInstrumentation.from(httpClientConfig, "akka.http.client") - httpClientInstrumentation - } + private[http] def rebuildHttpClientInstrumentation(): HttpClientInstrumentation = { + val httpClientConfig = Kamon.config().getConfig("kamon.instrumentation.akka.http.client") + httpClientInstrumentation = HttpClientInstrumentation.from(httpClientConfig, "akka.http.client") + httpClientInstrumentation + } - def handleResponse(responseFuture: Future[HttpResponse], handler: RequestHandler[HttpRequest]): Future[HttpResponse] = { + def handleResponse( + responseFuture: Future[HttpResponse], + handler: RequestHandler[HttpRequest] + ): Future[HttpResponse] = { responseFuture.onComplete { case Success(response) => handler.processResponse(toResponse(response)) - case Failure(t) => handler.span.fail(t).finish() + case Failure(t) => handler.span.fail(t).finish() }(CallingThreadExecutionContext) responseFuture diff --git a/instrumentation/kamon-akka-http/src/main/scala/kamon/instrumentation/akka/http/AkkaHttpInstrumentation.scala b/instrumentation/kamon-akka-http/src/main/scala/kamon/instrumentation/akka/http/AkkaHttpInstrumentation.scala index 3bdc6cd30..cccd84de9 100644 --- a/instrumentation/kamon-akka-http/src/main/scala/kamon/instrumentation/akka/http/AkkaHttpInstrumentation.scala +++ b/instrumentation/kamon-akka-http/src/main/scala/kamon/instrumentation/akka/http/AkkaHttpInstrumentation.scala @@ -45,18 +45,19 @@ object AkkaHttpInstrumentation { request.withHeaders(request.headers ++ _extraHeaders) } - def toResponseBuilder(response: HttpResponse): HttpMessage.ResponseBuilder[HttpResponse] = new HttpMessage.ResponseBuilder[HttpResponse] { - private var _headers = response.headers + def toResponseBuilder(response: HttpResponse): HttpMessage.ResponseBuilder[HttpResponse] = + new HttpMessage.ResponseBuilder[HttpResponse] { + private var _headers = response.headers - override def statusCode: Int = - response.status.intValue() + override def statusCode: Int = + response.status.intValue() - override def write(header: String, value: String): Unit = - _headers = RawHeader(header, value) +: _headers + override def write(header: String, value: String): Unit = + _headers = RawHeader(header, value) +: _headers - override def build(): HttpResponse = - response.withHeaders(_headers) - } + override def build(): HttpResponse = + response.withHeaders(_headers) + } /** * Bundles together the read parts of the HTTP Request mapping @@ -81,7 +82,7 @@ object AkkaHttpInstrumentation { override def read(header: String): Option[String] = { val headerValue = request.getHeader(header) - if(headerValue.isPresent) + if (headerValue.isPresent) Some(headerValue.get().value()) else None } diff --git a/instrumentation/kamon-akka-http/src/main/scala/kamon/instrumentation/akka/http/ServerFlowWrapper.scala b/instrumentation/kamon-akka-http/src/main/scala/kamon/instrumentation/akka/http/ServerFlowWrapper.scala index b942c658e..cd03af183 100644 --- a/instrumentation/kamon-akka-http/src/main/scala/kamon/instrumentation/akka/http/ServerFlowWrapper.scala +++ b/instrumentation/kamon-akka-http/src/main/scala/kamon/instrumentation/akka/http/ServerFlowWrapper.scala @@ -50,146 +50,169 @@ object ServerFlowWrapper { private val _defaultSettings = Settings("akka.http.server", "kamon.instrumentation.akka.http.server") @volatile private var _wrapperSettings = _defaultSettings - def apply(flow: Flow[HttpRequest, HttpResponse, NotUsed], interface: String, port: Int): Flow[HttpRequest, HttpResponse, NotUsed] = + def apply( + flow: Flow[HttpRequest, HttpResponse, NotUsed], + interface: String, + port: Int + ): Flow[HttpRequest, HttpResponse, NotUsed] = BidiFlow.fromGraph(wrapStage(_wrapperSettings, interface, port)).join(flow) - def wrapStage(settings: Settings, interface: String, port: Int) = new GraphStage[BidiShape[HttpRequest, HttpRequest, HttpResponse, HttpResponse]] { - val httpServerConfig = Kamon.config().getConfig(settings.configPath) - val httpServerInstrumentation = HttpServerInstrumentation.from(httpServerConfig, settings.component, interface, port) - val requestIn = Inlet.create[HttpRequest]("request.in") - val requestOut = Outlet.create[HttpRequest]("request.out") - val responseIn = Inlet.create[HttpResponse]("response.in") - val responseOut = Outlet.create[HttpResponse]("response.out") - - override val shape = BidiShape(requestIn, requestOut, responseIn, responseOut) - - override def createLogic(inheritedAttributes: Attributes) = new GraphStageLogic(shape) { - - // There might be more than one outstanding request when HTTP pipelining is enabled but according to the Akka HTTP - // documentation, it is required by the applications to generate responses for all requests and to generate them - // in the appropriate order, so we can simply queue and dequeue the RequestHandlers as the requests flow through - // the Stage. - // - // More info: https://doc.akka.io/docs/akka-http/current/server-side/low-level-api.html#request-response-cycle - private val _pendingRequests = mutable.Queue.empty[RequestHandler] - private val _createdAt = Kamon.clock().instant() - private var _completedRequests = 0 - - setHandler(requestIn, new InHandler { - override def onPush(): Unit = { - val request = grab(requestIn) - val requestHandler = httpServerInstrumentation.createHandler(toRequest(request), deferSamplingDecision = true) - .requestReceived() - - val defaultOperationName = httpServerInstrumentation.settings.defaultOperationName - val requestSpan = requestHandler.span - - // Automatic Operation name changes will only be allowed if the initial name HTTP Server didn't assign a - // user-defined name to the operation (that would be, either via an Operation Name Generator or a custom - // operation mapping). - val allowAutomaticChanges = requestSpan.operationName() == defaultOperationName - - _pendingRequests.enqueue(requestHandler) - - // The only reason why it's safe to leave the Thread dirty is because the Actor - // instrumentation will cleanup afterwards. - Kamon.storeContext(requestHandler.context.withEntry( - LastAutomaticOperationNameEdit.Key, Option(LastAutomaticOperationNameEdit(requestSpan.operationName(), allowAutomaticChanges)) - )) - - push(requestOut, request) - } + def wrapStage(settings: Settings, interface: String, port: Int) = + new GraphStage[BidiShape[HttpRequest, HttpRequest, HttpResponse, HttpResponse]] { + val httpServerConfig = Kamon.config().getConfig(settings.configPath) + val httpServerInstrumentation = + HttpServerInstrumentation.from(httpServerConfig, settings.component, interface, port) + val requestIn = Inlet.create[HttpRequest]("request.in") + val requestOut = Outlet.create[HttpRequest]("request.out") + val responseIn = Inlet.create[HttpResponse]("response.in") + val responseOut = Outlet.create[HttpResponse]("response.out") + + override val shape = BidiShape(requestIn, requestOut, responseIn, responseOut) + + override def createLogic(inheritedAttributes: Attributes) = new GraphStageLogic(shape) { + + // There might be more than one outstanding request when HTTP pipelining is enabled but according to the Akka HTTP + // documentation, it is required by the applications to generate responses for all requests and to generate them + // in the appropriate order, so we can simply queue and dequeue the RequestHandlers as the requests flow through + // the Stage. + // + // More info: https://doc.akka.io/docs/akka-http/current/server-side/low-level-api.html#request-response-cycle + private val _pendingRequests = mutable.Queue.empty[RequestHandler] + private val _createdAt = Kamon.clock().instant() + private var _completedRequests = 0 + + setHandler( + requestIn, + new InHandler { + override def onPush(): Unit = { + val request = grab(requestIn) + val requestHandler = + httpServerInstrumentation.createHandler(toRequest(request), deferSamplingDecision = true) + .requestReceived() + + val defaultOperationName = httpServerInstrumentation.settings.defaultOperationName + val requestSpan = requestHandler.span + + // Automatic Operation name changes will only be allowed if the initial name HTTP Server didn't assign a + // user-defined name to the operation (that would be, either via an Operation Name Generator or a custom + // operation mapping). + val allowAutomaticChanges = requestSpan.operationName() == defaultOperationName + + _pendingRequests.enqueue(requestHandler) + + // The only reason why it's safe to leave the Thread dirty is because the Actor + // instrumentation will cleanup afterwards. + Kamon.storeContext(requestHandler.context.withEntry( + LastAutomaticOperationNameEdit.Key, + Option(LastAutomaticOperationNameEdit(requestSpan.operationName(), allowAutomaticChanges)) + )) + + push(requestOut, request) + } - override def onUpstreamFinish(): Unit = - complete(requestOut) - }) - - setHandler(requestOut, new OutHandler { - override def onPull(): Unit = - pull(requestIn) - - override def onDownstreamFinish(): Unit = - cancel(requestIn) - }) - - setHandler(responseIn, new InHandler { - override def onPush(): Unit = { - val response = grab(responseIn) - val requestHandler = _pendingRequests.dequeue() - val requestSpan = requestHandler.span - val responseWithContext = requestHandler.buildResponse(toResponseBuilder(response), requestHandler.context) - - if(response.status.intValue() == 404 && requestSpan.operationName() == httpServerInstrumentation.settings.defaultOperationName) { - - // It might happen that if no route was able to handle the request or no directive that would force taking - // a sampling decision was run, the request would still not have any sampling decision so we both set the - // request as unhandled and take a sampling decision for that operation here. - requestSpan - .name(httpServerInstrumentation.settings.unhandledOperationName) - .takeSamplingDecision() + override def onUpstreamFinish(): Unit = + complete(requestOut) } + ) - val entity = if(responseWithContext.entity.isKnownEmpty()) { - requestHandler.responseSent(0L) - responseWithContext.entity - } else { - - requestSpan.mark("http.response.ready") - - responseWithContext.entity match { - case strict @ HttpEntity.Strict(_, bs) => - requestHandler.responseSent(bs.size) - strict - - case default: HttpEntity.Default => - requestHandler.responseSent(default.contentLength) - default - - case _ => - val responseSizeCounter = new AtomicLong(0L) - responseWithContext.entity.transformDataBytes( - Flow[ByteString] - .watchTermination()(Keep.right) - .wireTap(bs => responseSizeCounter.addAndGet(bs.size)) - .mapMaterializedValue { f => - f.andThen { - case Success(_) => - requestHandler.responseSent(responseSizeCounter.get()) - case Failure(e) => - requestSpan.fail("Response entity stream failed", e) - requestHandler.responseSent(responseSizeCounter.get()) - - }(CallingThreadExecutionContext) - } - ) - } - } + setHandler( + requestOut, + new OutHandler { + override def onPull(): Unit = + pull(requestIn) - _completedRequests += 1 - push(responseOut, responseWithContext.withEntity(entity)) - } + override def onDownstreamFinish(): Unit = + cancel(requestIn) + } + ) + + setHandler( + responseIn, + new InHandler { + override def onPush(): Unit = { + val response = grab(responseIn) + val requestHandler = _pendingRequests.dequeue() + val requestSpan = requestHandler.span + val responseWithContext = + requestHandler.buildResponse(toResponseBuilder(response), requestHandler.context) + + if ( + response.status.intValue() == 404 && requestSpan.operationName() == httpServerInstrumentation.settings.defaultOperationName + ) { + + // It might happen that if no route was able to handle the request or no directive that would force taking + // a sampling decision was run, the request would still not have any sampling decision so we both set the + // request as unhandled and take a sampling decision for that operation here. + requestSpan + .name(httpServerInstrumentation.settings.unhandledOperationName) + .takeSamplingDecision() + } + + val entity = if (responseWithContext.entity.isKnownEmpty()) { + requestHandler.responseSent(0L) + responseWithContext.entity + } else { + + requestSpan.mark("http.response.ready") + + responseWithContext.entity match { + case strict @ HttpEntity.Strict(_, bs) => + requestHandler.responseSent(bs.size) + strict + + case default: HttpEntity.Default => + requestHandler.responseSent(default.contentLength) + default + + case _ => + val responseSizeCounter = new AtomicLong(0L) + responseWithContext.entity.transformDataBytes( + Flow[ByteString] + .watchTermination()(Keep.right) + .wireTap(bs => responseSizeCounter.addAndGet(bs.size)) + .mapMaterializedValue { f => + f.andThen { + case Success(_) => + requestHandler.responseSent(responseSizeCounter.get()) + case Failure(e) => + requestSpan.fail("Response entity stream failed", e) + requestHandler.responseSent(responseSizeCounter.get()) + + }(CallingThreadExecutionContext) + } + ) + } + } + + _completedRequests += 1 + push(responseOut, responseWithContext.withEntity(entity)) + } - override def onUpstreamFinish(): Unit = - completeStage() - }) + override def onUpstreamFinish(): Unit = + completeStage() + } + ) - setHandler(responseOut, new OutHandler { - override def onPull(): Unit = - pull(responseIn) + setHandler( + responseOut, + new OutHandler { + override def onPull(): Unit = + pull(responseIn) - override def onDownstreamFinish(): Unit = - cancel(responseIn) - }) + override def onDownstreamFinish(): Unit = + cancel(responseIn) + } + ) - override def preStart(): Unit = - httpServerInstrumentation.connectionOpened() + override def preStart(): Unit = + httpServerInstrumentation.connectionOpened() - override def postStop(): Unit = { - val connectionLifetime = Duration.between(_createdAt, Kamon.clock().instant()) - httpServerInstrumentation.connectionClosed(connectionLifetime, _completedRequests) + override def postStop(): Unit = { + val connectionLifetime = Duration.between(_createdAt, Kamon.clock().instant()) + httpServerInstrumentation.connectionClosed(connectionLifetime, _completedRequests) + } } } - } def changeSettings(component: String, configPath: String): Unit = _wrapperSettings = Settings(component, configPath) @@ -198,9 +221,11 @@ object ServerFlowWrapper { _wrapperSettings = _defaultSettings def defaultOperationName(listenPort: Int): String = - _defaultOperationNames.getOrElseUpdate(listenPort, { - _serverInstrumentations.get(listenPort).map(_.settings.defaultOperationName).getOrElse("http.server.request") - }) + _defaultOperationNames.getOrElseUpdate( + listenPort, { + _serverInstrumentations.get(listenPort).map(_.settings.defaultOperationName).getOrElse("http.server.request") + } + ) case class Settings(component: String, configPath: String) } diff --git a/instrumentation/kamon-akka-http/src/main/scala/kamon/instrumentation/akka/http/TracingDirectives.scala b/instrumentation/kamon-akka-http/src/main/scala/kamon/instrumentation/akka/http/TracingDirectives.scala index 218bfc83b..e2eb9fffd 100644 --- a/instrumentation/kamon-akka-http/src/main/scala/kamon/instrumentation/akka/http/TracingDirectives.scala +++ b/instrumentation/kamon-akka-http/src/main/scala/kamon/instrumentation/akka/http/TracingDirectives.scala @@ -20,7 +20,6 @@ import akka.http.scaladsl.server.Directive0 import akka.http.scaladsl.server.directives.BasicDirectives import kamon.Kamon - trait TracingDirectives extends BasicDirectives { /** @@ -31,7 +30,7 @@ trait TracingDirectives extends BasicDirectives { val operationSpan = Kamon.currentSpan() operationSpan.name(name) - if(takeSamplingDecision) + if (takeSamplingDecision) operationSpan.takeSamplingDecision() req diff --git a/instrumentation/kamon-akka-http/src/test/scala/kamon/akka/http/AkkaHttpClientTracingSpec.scala b/instrumentation/kamon-akka-http/src/test/scala/kamon/akka/http/AkkaHttpClientTracingSpec.scala index 0322f9de1..4a9d8dde7 100644 --- a/instrumentation/kamon-akka-http/src/test/scala/kamon/akka/http/AkkaHttpClientTracingSpec.scala +++ b/instrumentation/kamon-akka-http/src/test/scala/kamon/akka/http/AkkaHttpClientTracingSpec.scala @@ -12,7 +12,7 @@ * either express or implied. See the License for the specific language governing permissions * and limitations under the License. * ========================================================================================= -*/ + */ package kamon.akka.http @@ -34,7 +34,8 @@ import org.scalatest.OptionValues import scala.concurrent.ExecutionContextExecutor import scala.concurrent.duration._ -class AkkaHttpClientTracingSpec extends AnyWordSpecLike with Matchers with InitAndStopKamonAfterAll with MetricInspection.Syntax +class AkkaHttpClientTracingSpec extends AnyWordSpecLike with Matchers with InitAndStopKamonAfterAll + with MetricInspection.Syntax with Reconfigure with TestWebServer with Eventually with OptionValues with TestSpanReporter { import TestWebServer.Endpoints._ @@ -90,7 +91,7 @@ class AkkaHttpClientTracingSpec extends AnyWordSpecLike with Matchers with InitA val httpResponse = response.value.value.get val headersMap = parse(httpResponse.data.utf8String).extract[Map[String, String]] - headersMap.keys.toList should contain allOf( + headersMap.keys.toList should contain allOf ( "context-tags", "X-Foo", "X-B3-TraceId", @@ -134,4 +135,3 @@ class AkkaHttpClientTracingSpec extends AnyWordSpecLike with Matchers with InitA webServer.shutdown() } } - diff --git a/instrumentation/kamon-akka-http/src/test/scala/kamon/akka/http/AkkaHttpServerMetricsSpec.scala b/instrumentation/kamon-akka-http/src/test/scala/kamon/akka/http/AkkaHttpServerMetricsSpec.scala index d76e48e25..b390a18bf 100644 --- a/instrumentation/kamon-akka-http/src/test/scala/kamon/akka/http/AkkaHttpServerMetricsSpec.scala +++ b/instrumentation/kamon-akka-http/src/test/scala/kamon/akka/http/AkkaHttpServerMetricsSpec.scala @@ -12,7 +12,7 @@ * either express or implied. See the License for the specific language governing permissions * and limitations under the License. * ========================================================================================= -*/ + */ package kamon.akka.http @@ -32,8 +32,9 @@ import org.scalatest.OptionValues import scala.concurrent.{ExecutionContextExecutor, Future} import scala.concurrent.duration._ -class AkkaHttpServerMetricsSpec extends AnyWordSpecLike with Matchers with InitAndStopKamonAfterAll with InstrumentInspection.Syntax - with Reconfigure with TestWebServer with Eventually with OptionValues { +class AkkaHttpServerMetricsSpec extends AnyWordSpecLike with Matchers with InitAndStopKamonAfterAll + with InstrumentInspection.Syntax + with Reconfigure with TestWebServer with Eventually with OptionValues { import TestWebServer.Endpoints._ @@ -50,18 +51,18 @@ class AkkaHttpServerMetricsSpec extends AnyWordSpecLike with Matchers with InitA "track the number of open connections and active requests on the Server side" in { val httpServerMetrics = HttpServerMetrics.of("akka.http.server", interface, port) - for(_ <- 1 to 8) yield { + for (_ <- 1 to 8) yield { sendRequest(HttpRequest(uri = s"http://$interface:$port/$waitTen")) } eventually(timeout(10 seconds)) { - httpServerMetrics.openConnections.distribution().max shouldBe(8) - httpServerMetrics.activeRequests.distribution().max shouldBe(8) + httpServerMetrics.openConnections.distribution().max shouldBe (8) + httpServerMetrics.activeRequests.distribution().max shouldBe (8) } eventually(timeout(20 seconds)) { - httpServerMetrics.openConnections.distribution().max shouldBe(0) - httpServerMetrics.activeRequests.distribution().max shouldBe(0) + httpServerMetrics.openConnections.distribution().max shouldBe (0) + httpServerMetrics.activeRequests.distribution().max shouldBe (0) } } } @@ -70,7 +71,7 @@ class AkkaHttpServerMetricsSpec extends AnyWordSpecLike with Matchers with InitA val connectionSettings = ClientConnectionSettings(system).withIdleTimeout(1 second) Source.single(request) .via(Http().outgoingConnection(interface, port, settings = connectionSettings)) - .map{r => + .map { r => r.discardEntityBytes() r } @@ -82,4 +83,3 @@ class AkkaHttpServerMetricsSpec extends AnyWordSpecLike with Matchers with InitA webServer.shutdown() } } - diff --git a/instrumentation/kamon-akka-http/src/test/scala/kamon/akka/http/AkkaHttpServerTracingSpec.scala b/instrumentation/kamon-akka-http/src/test/scala/kamon/akka/http/AkkaHttpServerTracingSpec.scala index 2f2883ab3..7bad768c5 100644 --- a/instrumentation/kamon-akka-http/src/test/scala/kamon/akka/http/AkkaHttpServerTracingSpec.scala +++ b/instrumentation/kamon-akka-http/src/test/scala/kamon/akka/http/AkkaHttpServerTracingSpec.scala @@ -12,7 +12,7 @@ * either express or implied. See the License for the specific language governing permissions * and limitations under the License. * ========================================================================================= -*/ + */ package kamon.akka.http @@ -34,8 +34,10 @@ import scala.collection.JavaConverters._ import scala.concurrent.ExecutionContextExecutor import scala.util.Try -class AkkaHttpServerTracingSpec extends AnyWordSpecLike with Matchers with ScalaFutures with Inside with InitAndStopKamonAfterAll - with MetricInspection.Syntax with Reconfigure with TestWebServer with Eventually with OptionValues with TestSpanReporter { +class AkkaHttpServerTracingSpec extends AnyWordSpecLike with Matchers with ScalaFutures with Inside + with InitAndStopKamonAfterAll + with MetricInspection.Syntax with Reconfigure with TestWebServer with Eventually with OptionValues + with TestSpanReporter { import TestWebServer.Endpoints._ @@ -74,7 +76,6 @@ class AkkaHttpServerTracingSpec extends AnyWordSpecLike with Matchers with Scala val target = s"$protocol://$interface:$port/$dummyPathOk" client.newCall(new Request.Builder().url(target).build()).execute() - eventually(timeout(10 seconds)) { val span = testSpanReporter().nextSpan().value span.tags.get(plain("http.url")) should endWith(s"$interface:$port/$dummyPathOk") @@ -220,7 +221,7 @@ class AkkaHttpServerTracingSpec extends AnyWordSpecLike with Matchers with Scala eventually(timeout(10 seconds)) { val span = testSpanReporter().nextSpan().value span.operationName shouldBe "unhandled" - span.tags.get(plain("http.url")) should endWith(s"$interface:$port/unknown-path") + span.tags.get(plain("http.url")) should endWith(s"$interface:$port/unknown-path") span.metricTags.get(plain("component")) shouldBe "akka.http.server" span.metricTags.get(plain("http.method")) shouldBe "GET" span.metricTags.get(plainBoolean("error")) shouldBe false @@ -243,11 +244,11 @@ class AkkaHttpServerTracingSpec extends AnyWordSpecLike with Matchers with Scala span } - inside(span.marks){ - case List(_ @ Mark(_, "http.response.ready")) => + inside(span.marks) { + case List(_ @Mark(_, "http.response.ready")) => } - span.tags.get(plain("http.url")) should endWith(s"$interface:$port/$stream") + span.tags.get(plain("http.url")) should endWith(s"$interface:$port/$stream") span.metricTags.get(plain("component")) shouldBe "akka.http.server" span.metricTags.get(plain("http.method")) shouldBe "GET" } @@ -280,4 +281,3 @@ class AkkaHttpServerTracingSpec extends AnyWordSpecLike with Matchers with Scala httpsWebServer.shutdown() } } - diff --git a/instrumentation/kamon-akka-http/src/test/scala/kamon/akka/http/ServerFlowWrapperSpec.scala b/instrumentation/kamon-akka-http/src/test/scala/kamon/akka/http/ServerFlowWrapperSpec.scala index f8ac71d5e..33766822d 100644 --- a/instrumentation/kamon-akka-http/src/test/scala/kamon/akka/http/ServerFlowWrapperSpec.scala +++ b/instrumentation/kamon-akka-http/src/test/scala/kamon/akka/http/ServerFlowWrapperSpec.scala @@ -24,10 +24,14 @@ class ServerFlowWrapperSpec extends AnyWordSpecLike with Matchers with ScalaFutu } private val defaultReturningFlow = Flow[HttpRequest].map { _ => - HttpResponse(status = StatusCodes.OK, entity = HttpEntity.Default( - ContentTypes.`text/plain(UTF-8)`, - 2, - Source.single(ByteString.apply("OK")))) + HttpResponse( + status = StatusCodes.OK, + entity = HttpEntity.Default( + ContentTypes.`text/plain(UTF-8)`, + 2, + Source.single(ByteString.apply("OK")) + ) + ) } "the server flow wrapper" should { diff --git a/instrumentation/kamon-akka-http/src/test/scala/kamon/testkit/TestNameGenerator.scala b/instrumentation/kamon-akka-http/src/test/scala/kamon/testkit/TestNameGenerator.scala index b8139f9a0..c1877a64e 100644 --- a/instrumentation/kamon-akka-http/src/test/scala/kamon/testkit/TestNameGenerator.scala +++ b/instrumentation/kamon-akka-http/src/test/scala/kamon/testkit/TestNameGenerator.scala @@ -20,8 +20,6 @@ import kamon.instrumentation.http.{HttpMessage, HttpOperationNameGenerator} class TestNameGenerator extends HttpOperationNameGenerator { - - // def serverOperationName(request: HttpRequest): String = { // val path = request.uri.path.toString() // // turns "/dummy-path" into "dummy" diff --git a/instrumentation/kamon-akka-http/src/test/scala/kamon/testkit/TestWebServer.scala b/instrumentation/kamon-akka-http/src/test/scala/kamon/testkit/TestWebServer.scala index b55551733..8ec1e2f34 100644 --- a/instrumentation/kamon-akka-http/src/test/scala/kamon/testkit/TestWebServer.scala +++ b/instrumentation/kamon-akka-http/src/test/scala/kamon/testkit/TestWebServer.scala @@ -57,56 +57,56 @@ trait TestWebServer extends TracingDirectives { } ~ pathPrefix("extraction") { authenticateBasic("realm", credentials => Option("Okay")) { srt => - (post | get) { - pathPrefix("nested") { - pathPrefix(IntNumber / "fixed") { num => - pathPrefix("anchor" / IntNumber.? / JavaUUID / "fixed") { (number, uuid) => - pathPrefix(LongNumber / HexIntNumber) { (longNum, hex) => - complete("OK") + (post | get) { + pathPrefix("nested") { + pathPrefix(IntNumber / "fixed") { num => + pathPrefix("anchor" / IntNumber.? / JavaUUID / "fixed") { (number, uuid) => + pathPrefix(LongNumber / HexIntNumber) { (longNum, hex) => + complete("OK") + } } } - } - } ~ - pathPrefix("concat") { - path("fixed" ~ JavaUUID ~ HexIntNumber) { (uuid, num) => - complete("OK") - } - } ~ - pathPrefix("on-complete" / IntNumber) { _ => - onComplete(Future("hello")) { _ => - extract(samplingDecision) { decision => - path("more-path") { - complete(decision.toString) + } ~ + pathPrefix("concat") { + path("fixed" ~ JavaUUID ~ HexIntNumber) { (uuid, num) => + complete("OK") + } + } ~ + pathPrefix("on-complete" / IntNumber) { _ => + onComplete(Future("hello")) { _ => + extract(samplingDecision) { decision => + path("more-path") { + complete(decision.toString) + } } } - } - } ~ - pathPrefix("on-success" / IntNumber) { _ => - onSuccess(Future("hello")) { text => - pathPrefix("after") { - complete(text) + } ~ + pathPrefix("on-success" / IntNumber) { _ => + onSuccess(Future("hello")) { text => + pathPrefix("after") { + complete(text) + } } - } - } ~ - pathPrefix("complete-or-recover-with" / IntNumber) { _ => - completeOrRecoverWith(Future("bad".charAt(10).toString)) { failure => - pathPrefix("after") { - failWith(failure) + } ~ + pathPrefix("complete-or-recover-with" / IntNumber) { _ => + completeOrRecoverWith(Future("bad".charAt(10).toString)) { failure => + pathPrefix("after") { + failWith(failure) + } } - } - } ~ - pathPrefix("complete-or-recover-with-success" / IntNumber) { _ => - completeOrRecoverWith(Future("good")) { failure => - pathPrefix("after") { - failWith(failure) + } ~ + pathPrefix("complete-or-recover-with-success" / IntNumber) { _ => + completeOrRecoverWith(Future("good")) { failure => + pathPrefix("after") { + failWith(failure) + } } + } ~ + path("segment" / Segment) { segment => + complete(HttpResponse(entity = HttpEntity(ContentTypes.`text/plain(UTF-8)`, segment))) } - } ~ - path("segment" / Segment){ segment => - complete(HttpResponse(entity = HttpEntity(ContentTypes.`text/plain(UTF-8)`, segment))) } } - } } ~ path(rootOk) { complete(OK) @@ -180,8 +180,13 @@ trait TestWebServer extends TracingDirectives { } } - if(https) - new WebServer(interface, port, "https", Http().bindAndHandleAsync(Route.asyncHandler(routes), interface, port, httpContext())) + if (https) + new WebServer( + interface, + port, + "https", + Http().bindAndHandleAsync(Route.asyncHandler(routes), interface, port, httpContext()) + ) else new WebServer(interface, port, "http", Http().bindAndHandle(routes, interface, port)) } @@ -216,7 +221,9 @@ trait TestWebServer extends TracingDirectives { } def loadX509Certificate(resourceName: String): Certificate = - CertificateFactory.getInstance("X.509").generateCertificate(getClass.getClassLoader.getResourceAsStream(resourceName)) + CertificateFactory.getInstance("X.509").generateCertificate( + getClass.getClassLoader.getResourceAsStream(resourceName) + ) def samplingDecision(ctx: RequestContext): Trace.SamplingDecision = Kamon.currentSpan().trace.samplingDecision @@ -239,7 +246,12 @@ trait TestWebServer extends TracingDirectives { } } - class WebServer(val interface: String, val port: Int, val protocol: String, bindingFuture: Future[Http.ServerBinding])(implicit ec: ExecutionContext) { + class WebServer( + val interface: String, + val port: Int, + val protocol: String, + bindingFuture: Future[Http.ServerBinding] + )(implicit ec: ExecutionContext) { def shutdown(): Future[_] = { bindingFuture.flatMap(binding => binding.unbind()) } diff --git a/instrumentation/kamon-annotation/src/main/scala/kamon/annotation/el/ELEvaluator.scala b/instrumentation/kamon-annotation/src/main/scala/kamon/annotation/el/ELEvaluator.scala index 61a5d3813..92de666ec 100644 --- a/instrumentation/kamon-annotation/src/main/scala/kamon/annotation/el/ELEvaluator.scala +++ b/instrumentation/kamon-annotation/src/main/scala/kamon/annotation/el/ELEvaluator.scala @@ -21,27 +21,27 @@ import java.util import kamon.annotation.el.EnhancedELProcessor.Syntax object StringEvaluator { - def evaluate(obj: AnyRef)(str:String): String = + def evaluate(obj: AnyRef)(str: String): String = ELProcessorFactory.withObject(obj).evalToString(str) - def evaluate(clazz: Class[_])(str:String): String = + def evaluate(clazz: Class[_])(str: String): String = ELProcessorFactory.withClass(clazz).evalToString(str) } object TagsEvaluator { - def evaluate(obj:AnyRef)(str:String): Map[String, String] = + def evaluate(obj: AnyRef)(str: String): Map[String, String] = ELProcessorFactory.withObject(obj).evalToMap(str) - def eval(obj:AnyRef)(str:String): util.Map[String, String] = { + def eval(obj: AnyRef)(str: String): util.Map[String, String] = { import scala.collection.JavaConverters._ evaluate(obj)(str).asJava } - def eval(clazz: Class[_])(str:String): util.Map[String, String] = { + def eval(clazz: Class[_])(str: String): util.Map[String, String] = { import scala.collection.JavaConverters._ evaluate(clazz)(str).asJava } - def evaluate(clazz: Class[_])(str:String): Map[String, String] = + def evaluate(clazz: Class[_])(str: String): Map[String, String] = ELProcessorFactory.withClass(clazz).evalToMap(str) -} \ No newline at end of file +} diff --git a/instrumentation/kamon-annotation/src/main/scala/kamon/annotation/el/EnhancedELProcessor.scala b/instrumentation/kamon-annotation/src/main/scala/kamon/annotation/el/EnhancedELProcessor.scala index 7bf342c54..490686f73 100644 --- a/instrumentation/kamon-annotation/src/main/scala/kamon/annotation/el/EnhancedELProcessor.scala +++ b/instrumentation/kamon-annotation/src/main/scala/kamon/annotation/el/EnhancedELProcessor.scala @@ -36,9 +36,13 @@ object EnhancedELProcessor { eval[String](str) match { case Success(value) => value case Failure(cause) => - Logger.warn(new Supplier[String] { - override def get(): String = s"${cause.getMessage} -> we will complete the operation with 'unknown' string" - }, cause) + Logger.warn( + new Supplier[String] { + override def get(): String = + s"${cause.getMessage} -> we will complete the operation with 'unknown' string" + }, + cause + ) "unknown" } } getOrElse expression @@ -47,9 +51,12 @@ object EnhancedELProcessor { eval[java.util.HashMap[String, String]](s"{$str}") match { case Success(value) ⇒ value.asInstanceOf[java.util.HashMap[String, String]].asScala.toMap case Failure(cause) ⇒ - Logger.warn(new Supplier[String] { - override def get(): String = s"${cause.getMessage} -> we will complete the operation with an empty map" - }, cause) + Logger.warn( + new Supplier[String] { + override def get(): String = s"${cause.getMessage} -> we will complete the operation with an empty map" + }, + cause + ) Map.empty[String, String] } } getOrElse Map.empty[String, String] @@ -58,7 +65,7 @@ object EnhancedELProcessor { private def extract(expression: String): Option[String] = expression match { case Pattern(ex) ⇒ Some(ex) - case _ ⇒ None + case _ ⇒ None } } } diff --git a/instrumentation/kamon-annotation/src/main/scala/kamon/annotation/util/Hooks.scala b/instrumentation/kamon-annotation/src/main/scala/kamon/annotation/util/Hooks.scala index 407917f68..bf366e057 100644 --- a/instrumentation/kamon-annotation/src/main/scala/kamon/annotation/util/Hooks.scala +++ b/instrumentation/kamon-annotation/src/main/scala/kamon/annotation/util/Hooks.scala @@ -29,20 +29,19 @@ object Hooks { def key(): Context.Key[Tracer.PreStartHook] = kamon.trace.Hooks.PreStart.Key - def updateOperationName(operationName:String): Tracer.PreStartHook = + def updateOperationName(operationName: String): Tracer.PreStartHook = kamon.trace.Hooks.PreStart.updateOperationName(operationName) def finishSpanOnComplete[T](future: Future[T], span: Span): Unit = future.onComplete { case Success(_) => span.finish() case Failure(t) => span.fail(t).finish() - } (CallingThreadExecutionContext) + }(CallingThreadExecutionContext) def decrementRangeSamplerOnComplete[T](future: Future[T], rangeSampler: RangeSampler): Unit = - future.onComplete { _ => rangeSampler.decrement() } (CallingThreadExecutionContext) + future.onComplete { _ => rangeSampler.decrement() }(CallingThreadExecutionContext) def stopTimerOnComplete[T](future: Future[T], timer: Timer.Started): Unit = - future.onComplete { _ => timer.stop() } (CallingThreadExecutionContext) - + future.onComplete { _ => timer.stop() }(CallingThreadExecutionContext) } diff --git a/instrumentation/kamon-annotation/src/test/scala/kamon/annotation/AnnotationInstrumentationSpec.scala b/instrumentation/kamon-annotation/src/test/scala/kamon/annotation/AnnotationInstrumentationSpec.scala index 250b8a353..44b7a8a04 100644 --- a/instrumentation/kamon-annotation/src/test/scala/kamon/annotation/AnnotationInstrumentationSpec.scala +++ b/instrumentation/kamon-annotation/src/test/scala/kamon/annotation/AnnotationInstrumentationSpec.scala @@ -36,21 +36,20 @@ import scala.concurrent.Future import scala.concurrent.ExecutionContext.Implicits.global class AnnotationInstrumentationSpec extends AnyWordSpec - with Matchers - with Eventually - with SpanSugar - with Reconfigure - with InstrumentInspection.Syntax - with SpanInspection - with MetricInspection.Syntax - with InitAndStopKamonAfterAll - with OptionValues { - + with Matchers + with Eventually + with SpanSugar + with Reconfigure + with InstrumentInspection.Syntax + with SpanInspection + with MetricInspection.Syntax + with InitAndStopKamonAfterAll + with OptionValues { "the Kamon Annotation module" should { "create a new Span for methods annotated with @Trace" in { - for (id <- 1 to 10) Annotated(id).trace() + for (id <- 1 to 10) Annotated(id).trace() eventually(timeout(3 seconds)) { val span = reporter.nextSpan().value @@ -119,8 +118,8 @@ class AnnotationInstrumentationSpec extends AnyWordSpec "count the invocations of a method annotated with @Count and evaluate EL expressions" in { for (id <- 1 to 2) Annotated(id).countWithEL() - Kamon.counter("counter:1").withTags(TagSet.from(Map("counter" -> "1", "env" -> "prod"))).value()should be(1) - Kamon.counter("counter:2").withTags(TagSet.from(Map("counter" -> "1", "env" -> "prod"))).value()should be(1) + Kamon.counter("counter:1").withTags(TagSet.from(Map("counter" -> "1", "env" -> "prod"))).value() should be(1) + Kamon.counter("counter:2").withTags(TagSet.from(Map("counter" -> "1", "env" -> "prod"))).value() should be(1) } "count the current invocations of a method annotated with @TrackConcurrency" in { @@ -175,8 +174,12 @@ class AnnotationInstrumentationSpec extends AnyWordSpec for (id <- 1 to 10) Annotated(id).trackConcurrencyWithEL() eventually(timeout(5 seconds)) { - Kamon.rangeSampler("minMax:1").withTags(TagSet.from(Map("minMax" -> "1", "env" -> "dev"))).distribution().sum should be(0) - Kamon.rangeSampler("minMax:2").withTags(TagSet.from(Map("minMax" -> "1", "env" -> "dev"))).distribution().sum should be(0) + Kamon.rangeSampler("minMax:1").withTags( + TagSet.from(Map("minMax" -> "1", "env" -> "dev")) + ).distribution().sum should be(0) + Kamon.rangeSampler("minMax:2").withTags( + TagSet.from(Map("minMax" -> "1", "env" -> "dev")) + ).distribution().sum should be(0) } } @@ -205,7 +208,9 @@ class AnnotationInstrumentationSpec extends AnyWordSpec "measure the time spent in the execution of a method annotated with @Time and evaluate EL expressions" in { for (id <- 1 to 1) Annotated(id).timeWithEL() - Kamon.timer("time:1").withTags(TagSet.from(Map("slow-service" -> "service", "env" -> "prod"))).distribution().count should be(1) + Kamon.timer("time:1").withTags( + TagSet.from(Map("slow-service" -> "service", "env" -> "prod")) + ).distribution().count should be(1) } "record the operationName returned by a method annotated with @Histogram" in { @@ -221,13 +226,15 @@ class AnnotationInstrumentationSpec extends AnyWordSpec "record the operationName returned by a method annotated with @Histogram and evaluate EL expressions" in { for (operationName <- 1 to 2) Annotated(operationName).histogramWithEL(operationName) - val snapshot1 = Kamon.histogram("histogram:1").withTags(TagSet.from(Map("histogram" -> "hdr", "env" -> "prod"))).distribution() + val snapshot1 = + Kamon.histogram("histogram:1").withTags(TagSet.from(Map("histogram" -> "hdr", "env" -> "prod"))).distribution() snapshot1.count should be(1) snapshot1.min should be(1) snapshot1.max should be(1) snapshot1.sum should be(1) - val snapshot2 = Kamon.histogram("histogram:2").withTags(TagSet.from(Map("histogram" -> "hdr", "env" -> "prod"))).distribution() + val snapshot2 = + Kamon.histogram("histogram:2").withTags(TagSet.from(Map("histogram" -> "hdr", "env" -> "prod"))).distribution() snapshot2.count should be(1) snapshot2.min should be(2) snapshot2.max should be(2) @@ -271,7 +278,7 @@ case class Annotated(id: Long) { def traceWithCompletionStage(): CompletionStage[String] = CompletableFuture.completedFuture("Hello") - @CustomizeInnerSpan(operationName = "customized-operation-name" ) + @CustomizeInnerSpan(operationName = "customized-operation-name") def traceWithSpanCustomizer(): Unit = { val spanBuilder = Kamon.spanBuilder("unknown").tag("slow-service", "service").tag("env", "prod").start() @@ -329,10 +336,9 @@ case class Annotated(id: Long) { @Histogram(name = "#{'histogram:' += this.id}", tags = "${'histogram':'hdr', 'env':'prod'}") def histogramWithEL(operationName: Long): Long = operationName - def customizeSpan():Unit = {} + def customizeSpan(): Unit = {} } object Annotated { def apply(): Annotated = new Annotated(0L) } - diff --git a/instrumentation/kamon-annotation/src/test/scala/kamon/annotation/StaticAnnotationInstrumentationJavaSpec.scala b/instrumentation/kamon-annotation/src/test/scala/kamon/annotation/StaticAnnotationInstrumentationJavaSpec.scala index 920e3d837..24cb1c4f2 100644 --- a/instrumentation/kamon-annotation/src/test/scala/kamon/annotation/StaticAnnotationInstrumentationJavaSpec.scala +++ b/instrumentation/kamon-annotation/src/test/scala/kamon/annotation/StaticAnnotationInstrumentationJavaSpec.scala @@ -29,15 +29,15 @@ import org.scalatest.OptionValues import org.scalatest.wordspec.AnyWordSpec class StaticAnnotationInstrumentationJavaSpec extends AnyWordSpec - with Matchers - with Eventually - with SpanSugar - with Reconfigure - with InstrumentInspection.Syntax - with SpanInspection - with MetricInspection.Syntax - with InitAndStopKamonAfterAll - with OptionValues { + with Matchers + with Eventually + with SpanSugar + with Reconfigure + with InstrumentInspection.Syntax + with SpanInspection + with MetricInspection.Syntax + with InitAndStopKamonAfterAll + with OptionValues { "the Kamon Annotation module" should { "create a new trace when is invoked a static method annotated with @Trace" in { @@ -67,7 +67,7 @@ class StaticAnnotationInstrumentationJavaSpec extends AnyWordSpec "count the invocations of a static method annotated with @Count and evaluate EL expressions" in { for (_ <- 1 to 2) AnnotatedJavaClass.countWithEL() - Kamon.counter("count:10").withTags(TagSet.from(Map("counter" -> "1", "env" -> "prod"))).value()should be(2) + Kamon.counter("count:10").withTags(TagSet.from(Map("counter" -> "1", "env" -> "prod"))).value() should be(2) } "count the current invocations of a static method annotated with @TrackConcurrency" in { @@ -82,7 +82,9 @@ class StaticAnnotationInstrumentationJavaSpec extends AnyWordSpec for (_ <- 1 to 10) AnnotatedJavaClass.countMinMaxWithEL() eventually(timeout(5 seconds)) { - Kamon.rangeSampler("minMax:10").withTags(TagSet.from(Map("minMax" -> "1", "env" -> "dev"))).distribution().sum should be(0) + Kamon.rangeSampler("minMax:10").withTags( + TagSet.from(Map("minMax" -> "1", "env" -> "dev")) + ).distribution().sum should be(0) } } @@ -95,7 +97,9 @@ class StaticAnnotationInstrumentationJavaSpec extends AnyWordSpec "measure the time spent in the execution of a static method annotated with @Time and evaluate EL expressions" in { for (_ <- 1 to 1) AnnotatedJavaClass.timeWithEL() - Kamon.timer("time:10").withTags(TagSet.from(Map("slow-service" -> "service", "env" -> "prod"))).distribution().count should be(1) + Kamon.timer("time:10").withTags( + TagSet.from(Map("slow-service" -> "service", "env" -> "prod")) + ).distribution().count should be(1) } "record the operationName returned by a static method annotated with @Histogram" in { @@ -111,7 +115,8 @@ class StaticAnnotationInstrumentationJavaSpec extends AnyWordSpec "record the operationName returned by a static method annotated with @Histogram and evaluate EL expressions" in { for (operationName <- 1 to 2) AnnotatedJavaClass.histogramWithEL(operationName.toLong) - val snapshot = Kamon.histogram("histogram:10").withTags(TagSet.from(Map("histogram" -> "hdr", "env" -> "prod"))).distribution() + val snapshot = + Kamon.histogram("histogram:10").withTags(TagSet.from(Map("histogram" -> "hdr", "env" -> "prod"))).distribution() snapshot.count should be(2) snapshot.min should be(1) snapshot.max should be(2) @@ -136,4 +141,4 @@ class StaticAnnotationInstrumentationJavaSpec extends AnyWordSpec def stringTag(span: Span.Finished)(tag: String): String = { span.tags.get(plain(tag)) } -} \ No newline at end of file +} diff --git a/instrumentation/kamon-annotation/src/test/scala/kamon/annotation/StaticAnnotationInstrumentationSpec.scala b/instrumentation/kamon-annotation/src/test/scala/kamon/annotation/StaticAnnotationInstrumentationSpec.scala index 11b339d29..903de10db 100644 --- a/instrumentation/kamon-annotation/src/test/scala/kamon/annotation/StaticAnnotationInstrumentationSpec.scala +++ b/instrumentation/kamon-annotation/src/test/scala/kamon/annotation/StaticAnnotationInstrumentationSpec.scala @@ -30,19 +30,19 @@ import org.scalatest.wordspec.AnyWordSpec import org.scalatest.OptionValues class StaticAnnotationInstrumentationSpec extends AnyWordSpec - with Matchers - with Eventually - with SpanSugar - with Reconfigure - with InstrumentInspection.Syntax - with SpanInspection - with MetricInspection.Syntax - with InitAndStopKamonAfterAll - with OptionValues { + with Matchers + with Eventually + with SpanSugar + with Reconfigure + with InstrumentInspection.Syntax + with SpanInspection + with MetricInspection.Syntax + with InitAndStopKamonAfterAll + with OptionValues { "the Kamon Annotation module" should { "create a new trace when is invoked a method annotated with @Trace in a Scala Object" in { - for (_<- 1 to 10) AnnotatedObject.trace() + for (_ <- 1 to 10) AnnotatedObject.trace() eventually(timeout(10 seconds)) { val span = reporter.nextSpan().value @@ -68,7 +68,7 @@ class StaticAnnotationInstrumentationSpec extends AnyWordSpec "count the invocations of a method annotated with @Count and evaluate EL expressions in a Scala Object" in { for (_ <- 1 to 2) AnnotatedObject.countWithEL() - Kamon.counter("count:10").withTags(TagSet.from(Map("counter" -> "1", "env" -> "prod"))).value()should be(2) + Kamon.counter("count:10").withTags(TagSet.from(Map("counter" -> "1", "env" -> "prod"))).value() should be(2) } "count the current invocations of a method annotated with @TrackConcurrency in a Scala Object" in { @@ -85,7 +85,9 @@ class StaticAnnotationInstrumentationSpec extends AnyWordSpec for (_ <- 1 to 10) AnnotatedObject.countMinMaxWithEL() eventually(timeout(5 seconds)) { - Kamon.rangeSampler("minMax:10").withTags(TagSet.from(Map("minMax" -> "1", "env" -> "dev"))).distribution().sum should be(0) + Kamon.rangeSampler("minMax:10").withTags( + TagSet.from(Map("minMax" -> "1", "env" -> "dev")) + ).distribution().sum should be(0) } } @@ -98,7 +100,9 @@ class StaticAnnotationInstrumentationSpec extends AnyWordSpec "measure the time spent in the execution of a method annotated with @Time and evaluate EL expressions in a Scala Object" in { AnnotatedObject.timeWithEL() - Kamon.timer("time:10").withTags(TagSet.from(Map("slow-service" -> "service", "env" -> "prod"))).distribution().count should be(1) + Kamon.timer("time:10").withTags( + TagSet.from(Map("slow-service" -> "service", "env" -> "prod")) + ).distribution().count should be(1) } "record the operationName returned by a method annotated with @Histogram in a Scala Object" in { @@ -114,7 +118,8 @@ class StaticAnnotationInstrumentationSpec extends AnyWordSpec "record the operationName returned by a method annotated with @Histogram and evaluate EL expressions in a Scala Object" in { for (operationName <- 1 to 2) AnnotatedObject.histogramWithEL(operationName) - val snapshot = Kamon.histogram("histogram:10").withTags(TagSet.from(Map("histogram" -> "hdr", "env" -> "prod"))).distribution() + val snapshot = + Kamon.histogram("histogram:10").withTags(TagSet.from(Map("histogram" -> "hdr", "env" -> "prod"))).distribution() snapshot.count should be(2) snapshot.min should be(1) snapshot.max should be(2) @@ -174,4 +179,4 @@ object AnnotatedObject { @Histogram(name = "#{'histogram:' += AnnotatedObject$.MODULE$.Id}", tags = "${'histogram':'hdr', 'env':'prod'}") def histogramWithEL(operationName: Long): Long = operationName -} \ No newline at end of file +} diff --git a/instrumentation/kamon-aws-sdk/src/main/scala/kamon/instrumentation/aws/sdk/AwsSdkClientExecutionInterceptor.scala b/instrumentation/kamon-aws-sdk/src/main/scala/kamon/instrumentation/aws/sdk/AwsSdkClientExecutionInterceptor.scala index 71538aed3..8bd785e9e 100644 --- a/instrumentation/kamon-aws-sdk/src/main/scala/kamon/instrumentation/aws/sdk/AwsSdkClientExecutionInterceptor.scala +++ b/instrumentation/kamon-aws-sdk/src/main/scala/kamon/instrumentation/aws/sdk/AwsSdkClientExecutionInterceptor.scala @@ -18,7 +18,13 @@ package kamon.instrumentation.aws.sdk import kamon.Kamon import kamon.trace.Span -import software.amazon.awssdk.core.interceptor.{Context, ExecutionAttribute, ExecutionAttributes, ExecutionInterceptor, SdkExecutionAttribute} +import software.amazon.awssdk.core.interceptor.{ + Context, + ExecutionAttribute, + ExecutionAttributes, + ExecutionInterceptor, + SdkExecutionAttribute +} /** * Execution Interceptor for the AWS Java SDK Version 2.x @@ -31,7 +37,7 @@ class AwsSdkClientExecutionInterceptor extends ExecutionInterceptor { import AwsSdkClientExecutionInterceptor.ClientSpanAttribute override def afterMarshalling(context: Context.AfterMarshalling, executionAttributes: ExecutionAttributes): Unit = { - if(Kamon.enabled()) { + if (Kamon.enabled()) { val operationName = executionAttributes.getAttribute(SdkExecutionAttribute.OPERATION_NAME) val serviceName = executionAttributes.getAttribute(SdkExecutionAttribute.SERVICE_NAME) val clientType = executionAttributes.getAttribute(SdkExecutionAttribute.CLIENT_TYPE) @@ -45,16 +51,16 @@ class AwsSdkClientExecutionInterceptor extends ExecutionInterceptor { } override def afterExecution(context: Context.AfterExecution, executionAttributes: ExecutionAttributes): Unit = { - if(Kamon.enabled()) { + if (Kamon.enabled()) { val kamonSpan = executionAttributes.getAttribute(ClientSpanAttribute) - if(kamonSpan != null) { + if (kamonSpan != null) { kamonSpan.finish() } } } override def onExecutionFailure(context: Context.FailedExecution, executionAttributes: ExecutionAttributes): Unit = { - if(Kamon.enabled()) { + if (Kamon.enabled()) { val kamonSpan = executionAttributes.getAttribute(ClientSpanAttribute) if (kamonSpan != null) { kamonSpan.fail(context.exception()).finish() @@ -65,4 +71,4 @@ class AwsSdkClientExecutionInterceptor extends ExecutionInterceptor { object AwsSdkClientExecutionInterceptor { private val ClientSpanAttribute = new ExecutionAttribute[Span]("SdkClientSpan") -} \ No newline at end of file +} diff --git a/instrumentation/kamon-aws-sdk/src/main/scala/kamon/instrumentation/aws/sdk/AwsSdkRequestHandler.scala b/instrumentation/kamon-aws-sdk/src/main/scala/kamon/instrumentation/aws/sdk/AwsSdkRequestHandler.scala index 554daf1e2..913cc83aa 100644 --- a/instrumentation/kamon-aws-sdk/src/main/scala/kamon/instrumentation/aws/sdk/AwsSdkRequestHandler.scala +++ b/instrumentation/kamon-aws-sdk/src/main/scala/kamon/instrumentation/aws/sdk/AwsSdkRequestHandler.scala @@ -32,7 +32,7 @@ class AwsSdkRequestHandler extends RequestHandler2 { import AwsSdkRequestHandler.SpanContextKey override def beforeRequest(request: Request[_]): Unit = { - if(Kamon.enabled()) { + if (Kamon.enabled()) { val serviceName = request.getServiceName val originalRequestName = { // Remove the "Request" part of the request class name, if present @@ -46,7 +46,7 @@ class AwsSdkRequestHandler extends RequestHandler2 { val clientSpan = serviceName match { case "AmazonSQS" => Kamon.producerSpanBuilder(operationName, serviceName).start() - case _ => Kamon.clientSpanBuilder(operationName, serviceName).start() + case _ => Kamon.clientSpanBuilder(operationName, serviceName).start() } request.addHandlerContext(SpanContextKey, clientSpan) @@ -54,7 +54,7 @@ class AwsSdkRequestHandler extends RequestHandler2 { } override def afterResponse(request: Request[_], response: Response[_]): Unit = { - if(Kamon.enabled()) { + if (Kamon.enabled()) { val requestSpan = request.getHandlerContext(SpanContextKey) if (requestSpan != null) { requestSpan.finish() @@ -63,7 +63,7 @@ class AwsSdkRequestHandler extends RequestHandler2 { } override def afterError(request: Request[_], response: Response[_], e: Exception): Unit = { - if(Kamon.enabled()) { + if (Kamon.enabled()) { val requestSpan = request.getHandlerContext(SpanContextKey) if (requestSpan != null) { requestSpan @@ -76,4 +76,4 @@ class AwsSdkRequestHandler extends RequestHandler2 { object AwsSdkRequestHandler { private val SpanContextKey = new HandlerContextKey[Span](classOf[Span].getName) -} \ No newline at end of file +} diff --git a/instrumentation/kamon-aws-sdk/src/test/scala/kamon/instrumentation/aws/sdk/DynamoDBTracingSpec.scala b/instrumentation/kamon-aws-sdk/src/test/scala/kamon/instrumentation/aws/sdk/DynamoDBTracingSpec.scala index 87da97361..60dc4bf88 100644 --- a/instrumentation/kamon-aws-sdk/src/test/scala/kamon/instrumentation/aws/sdk/DynamoDBTracingSpec.scala +++ b/instrumentation/kamon-aws-sdk/src/test/scala/kamon/instrumentation/aws/sdk/DynamoDBTracingSpec.scala @@ -26,12 +26,19 @@ import org.testcontainers.containers.GenericContainer import software.amazon.awssdk.auth.credentials.{AwsBasicCredentials, StaticCredentialsProvider} import software.amazon.awssdk.regions.Region import software.amazon.awssdk.services.dynamodb.DynamoDbClient -import software.amazon.awssdk.services.dynamodb.model.{AttributeDefinition, CreateTableRequest, KeySchemaElement, KeyType, ProvisionedThroughput} +import software.amazon.awssdk.services.dynamodb.model.{ + AttributeDefinition, + CreateTableRequest, + KeySchemaElement, + KeyType, + ProvisionedThroughput +} import scala.concurrent.duration._ import java.net.URI -class DynamoDBTracingSpec extends AnyWordSpec with Matchers with OptionValues with InitAndStopKamonAfterAll with Eventually with TestSpanReporter { +class DynamoDBTracingSpec extends AnyWordSpec with Matchers with OptionValues with InitAndStopKamonAfterAll + with Eventually with TestSpanReporter { val dynamoPort = 8000 val dynamoContainer: GenericContainer[_] = new GenericContainer("amazon/dynamodb-local:latest") .withExposedPorts(dynamoPort) @@ -42,17 +49,15 @@ class DynamoDBTracingSpec extends AnyWordSpec with Matchers with OptionValues wi .region(Region.US_EAST_1) .build() - "the DynamoDB instrumentation on the SDK" should { "create a Span for simple calls" in { client.createTable(CreateTableRequest.builder() .tableName("people") .attributeDefinitions(AttributeDefinition.builder().attributeName("customerId").attributeType("S").build()) .keySchema(KeySchemaElement.builder().attributeName("customerId").keyType(KeyType.HASH).build()) - .provisionedThroughput(ProvisionedThroughput.builder().readCapacityUnits(5l).writeCapacityUnits(5l).build()) + .provisionedThroughput(ProvisionedThroughput.builder().readCapacityUnits(5L).writeCapacityUnits(5L).build()) .build()) - eventually(timeout(5 seconds)) { val span = testSpanReporter().nextSpan().value span.operationName shouldBe "CreateTable" diff --git a/instrumentation/kamon-caffeine/src/main/scala/kamon/instrumentation/caffeine/CaffeineCacheInstrumentation.scala b/instrumentation/kamon-caffeine/src/main/scala/kamon/instrumentation/caffeine/CaffeineCacheInstrumentation.scala index da32ee61a..2d1cebfad 100644 --- a/instrumentation/kamon-caffeine/src/main/scala/kamon/instrumentation/caffeine/CaffeineCacheInstrumentation.scala +++ b/instrumentation/kamon-caffeine/src/main/scala/kamon/instrumentation/caffeine/CaffeineCacheInstrumentation.scala @@ -41,9 +41,7 @@ object GetIfPresentAdvice { } @Advice.OnMethodExit(suppress = classOf[Throwable]) - @static def exit(@Advice.Enter span: Span, - @Advice.Return ret: Any, - @Advice.Argument(0) key: Any): Unit = { + @static def exit(@Advice.Enter span: Span, @Advice.Return ret: Any, @Advice.Argument(0) key: Any): Unit = { if (ret == null) { span.tag("cache.miss", s"No value for key $key") } diff --git a/instrumentation/kamon-caffeine/src/main/scala/kamon/instrumentation/caffeine/KamonStatsCounter.scala b/instrumentation/kamon-caffeine/src/main/scala/kamon/instrumentation/caffeine/KamonStatsCounter.scala index 0c7103758..c8817df51 100644 --- a/instrumentation/kamon-caffeine/src/main/scala/kamon/instrumentation/caffeine/KamonStatsCounter.scala +++ b/instrumentation/kamon-caffeine/src/main/scala/kamon/instrumentation/caffeine/KamonStatsCounter.scala @@ -23,7 +23,6 @@ class KamonStatsCounter(name: String) extends StatsCounter { override def recordLoadFailure(loadTime: Long): Unit = loadFailureTime.record(loadTime) - override def recordEviction(): Unit = { evictionCount.increment() } diff --git a/instrumentation/kamon-caffeine/src/test/scala/kamon/instrumentation/caffeine/CaffeineAsyncCacheSpec.scala b/instrumentation/kamon-caffeine/src/test/scala/kamon/instrumentation/caffeine/CaffeineAsyncCacheSpec.scala index d3618f65b..511613e27 100644 --- a/instrumentation/kamon-caffeine/src/test/scala/kamon/instrumentation/caffeine/CaffeineAsyncCacheSpec.scala +++ b/instrumentation/kamon-caffeine/src/test/scala/kamon/instrumentation/caffeine/CaffeineAsyncCacheSpec.scala @@ -12,7 +12,7 @@ import java.util.concurrent.CompletableFuture import scala.concurrent.duration.DurationInt class CaffeineAsyncCacheSpec - extends AnyWordSpec + extends AnyWordSpec with Matchers with BeforeAndAfterAll with TestSpanReporter { @@ -28,9 +28,12 @@ class CaffeineAsyncCacheSpec } "not create a span when using get" in { - cache.get("a", new java.util.function.Function[String, String] { - override def apply(a: String): String = "value" - }) + cache.get( + "a", + new java.util.function.Function[String, String] { + override def apply(a: String): String = "value" + } + ) eventually(timeout(2.seconds)) { testSpanReporter().spans() shouldBe empty } diff --git a/instrumentation/kamon-caffeine/src/test/scala/kamon/instrumentation/caffeine/CaffeineSyncCacheSpec.scala b/instrumentation/kamon-caffeine/src/test/scala/kamon/instrumentation/caffeine/CaffeineSyncCacheSpec.scala index 8078d6ef1..8bb0125ea 100644 --- a/instrumentation/kamon-caffeine/src/test/scala/kamon/instrumentation/caffeine/CaffeineSyncCacheSpec.scala +++ b/instrumentation/kamon-caffeine/src/test/scala/kamon/instrumentation/caffeine/CaffeineSyncCacheSpec.scala @@ -12,7 +12,7 @@ import scala.collection.JavaConverters._ import scala.concurrent.duration.DurationInt class CaffeineSyncCacheSpec - extends AnyWordSpec + extends AnyWordSpec with Matchers with InitAndStopKamonAfterAll with TestSpanReporter { @@ -30,9 +30,12 @@ class CaffeineSyncCacheSpec } "create a span when accessing an existing key" in { - cache.get("a", new java.util.function.Function[String, String] { - override def apply(a: String): String = "value" - }) + cache.get( + "a", + new java.util.function.Function[String, String] { + override def apply(a: String): String = "value" + } + ) eventually(timeout(2.seconds)) { val span = testSpanReporter().nextSpan().value span.operationName shouldBe "caffeine.computeIfAbsent" diff --git a/instrumentation/kamon-cassandra/src/main/scala/com/datastax/driver/core/ConnectionPoolAdvices.scala b/instrumentation/kamon-cassandra/src/main/scala/com/datastax/driver/core/ConnectionPoolAdvices.scala index edd2c82cb..df7d148f4 100644 --- a/instrumentation/kamon-cassandra/src/main/scala/com/datastax/driver/core/ConnectionPoolAdvices.scala +++ b/instrumentation/kamon-cassandra/src/main/scala/com/datastax/driver/core/ConnectionPoolAdvices.scala @@ -31,20 +31,23 @@ object PoolConstructorAdvice { @Advice.OnMethodExit @static def onConstructed( - @Advice.This poolWithMetrics: HostConnectionPool with HasPoolMetrics, - @Advice.FieldValue("host") host: Host, - @Advice.FieldValue("totalInFlight") totalInflight: AtomicInteger + @Advice.This poolWithMetrics: HostConnectionPool with HasPoolMetrics, + @Advice.FieldValue("host") host: Host, + @Advice.FieldValue("totalInFlight") totalInflight: AtomicInteger ): Unit = { - val node = CassandraInstrumentation.createNode(host) + val node = CassandraInstrumentation.createNode(host) val samplingInterval = CassandraInstrumentation.settings.sampleInterval poolWithMetrics.setNodeMonitor(new NodeMonitor(node)) - if(poolWithMetrics.nodeMonitor.poolMetricsEnabled) { - poolWithMetrics.nodeMonitor.poolMetrics.inFlight.autoUpdate(inFlightTracker => { - inFlightTracker.record(totalInflight.longValue()) - () - }, samplingInterval) + if (poolWithMetrics.nodeMonitor.poolMetricsEnabled) { + poolWithMetrics.nodeMonitor.poolMetrics.inFlight.autoUpdate( + inFlightTracker => { + inFlightTracker.record(totalInflight.longValue()) + () + }, + samplingInterval + ) } } } @@ -72,10 +75,10 @@ object BorrowAdvice { @Advice.OnMethodExit(suppress = classOf[Throwable], inline = false) @static def onBorrowed( - @Advice.Return connection: ListenableFuture[Connection], - @Advice.Enter start: Long, - @Advice.This poolMetrics: HasPoolMetrics, - @Advice.FieldValue("totalInFlight") totalInflight: AtomicInteger + @Advice.Return connection: ListenableFuture[Connection], + @Advice.Enter start: Long, + @Advice.This poolMetrics: HasPoolMetrics, + @Advice.FieldValue("totalInFlight") totalInflight: AtomicInteger ): Unit = { GuavaCompatibility.INSTANCE.addCallback( @@ -100,16 +103,19 @@ object InitPoolAdvice { @Advice.OnMethodExit @static def onPoolInited( - @Advice.This hasPoolMetrics: HasPoolMetrics, - @Advice.Return done: ListenableFuture[_], - @Advice.FieldValue("open") openConnections: AtomicInteger + @Advice.This hasPoolMetrics: HasPoolMetrics, + @Advice.Return done: ListenableFuture[_], + @Advice.FieldValue("open") openConnections: AtomicInteger ): Unit = { - done.addListener(new Runnable { - override def run(): Unit = { - hasPoolMetrics.nodeMonitor.connectionsOpened(openConnections.get()) - } - }, CallingThreadExecutionContext) + done.addListener( + new Runnable { + override def run(): Unit = { + hasPoolMetrics.nodeMonitor.connectionsOpened(openConnections.get()) + } + }, + CallingThreadExecutionContext + ) } } @@ -118,8 +124,8 @@ object CreateConnectionAdvice { @Advice.OnMethodExit @static def onConnectionCreated( - @Advice.This hasPoolMetrics: HasPoolMetrics, - @Advice.Return created: Boolean + @Advice.This hasPoolMetrics: HasPoolMetrics, + @Advice.Return created: Boolean ): Unit = if (created) { hasPoolMetrics.nodeMonitor.connectionsOpened(1) @@ -131,8 +137,8 @@ object TrashConnectionAdvice { @Advice.OnMethodExit @static def onConnectionTrashed( - @Advice.This hasPoolMetrics: HasPoolMetrics, - @Advice.FieldValue("host") host: Host + @Advice.This hasPoolMetrics: HasPoolMetrics, + @Advice.FieldValue("host") host: Host ): Unit = { hasPoolMetrics.nodeMonitor.connectionTrashed } diff --git a/instrumentation/kamon-cassandra/src/main/scala/com/datastax/driver/core/ExecutionAdvices.scala b/instrumentation/kamon-cassandra/src/main/scala/com/datastax/driver/core/ExecutionAdvices.scala index 77fe4b5e1..36179e89d 100644 --- a/instrumentation/kamon-cassandra/src/main/scala/com/datastax/driver/core/ExecutionAdvices.scala +++ b/instrumentation/kamon-cassandra/src/main/scala/com/datastax/driver/core/ExecutionAdvices.scala @@ -36,7 +36,7 @@ object QueryOperations { val QueryOperationName = "cassandra.query" val BatchOperationName = "cassandra.batch" val QueryPrepareOperationName: String = QueryOperationName + ".prepare" - val ExecutionOperationName: String = QueryOperationName + ".execution" + val ExecutionOperationName: String = QueryOperationName + ".execution" } class QueryExecutionAdvice @@ -47,15 +47,15 @@ object QueryExecutionAdvice { @Advice.OnMethodEnter @static def onQueryExec( - @Advice.This execution: HasContext, - @Advice.Argument(0) host: Host with HasPoolMetrics, - @Advice.FieldValue("position") position: Int, - @Advice.FieldValue("queryStateRef") queryState: AtomicReference[QueryState] + @Advice.This execution: HasContext, + @Advice.Argument(0) host: Host with HasPoolMetrics, + @Advice.FieldValue("position") position: Int, + @Advice.FieldValue("queryStateRef") queryState: AtomicReference[QueryState] ): Unit = { val nodeMonitor = host.nodeMonitor val clientSpan = Kamon.currentSpan() - val executionSpan = if(CassandraInstrumentation.settings.createRoundTripSpans) { + val executionSpan = if (CassandraInstrumentation.settings.createRoundTripSpans) { Kamon .clientSpanBuilder(ExecutionOperationName, Tags.CassandraDriverComponent) .asChildOf(clientSpan) @@ -91,8 +91,8 @@ object OnResultSetConstruction { @Advice.OnMethodExit @static def onCreateResultSet( - @Advice.Return rs: ArrayBackedResultSet, - @Advice.Argument(0) msg: Responses.Result with HasContext + @Advice.Return rs: ArrayBackedResultSet, + @Advice.Argument(0) msg: Responses.Result with HasContext ): Unit = if (rs.isInstanceOf[HasContext]) { rs.asInstanceOf[HasContext].setContext(msg.context) } @@ -132,10 +132,10 @@ object OnSetAdvice { @Advice.OnMethodEnter @static def onSetResult( - @Advice.This execution: Connection.ResponseCallback with HasContext, - @Advice.Argument(0) connection: Connection, - @Advice.Argument(1) response: Message.Response, - @Advice.FieldValue("current") currentHost: Host with HasPoolMetrics + @Advice.This execution: Connection.ResponseCallback with HasContext, + @Advice.Argument(0) connection: Connection, + @Advice.Argument(1) response: Message.Response, + @Advice.FieldValue("current") currentHost: Host with HasPoolMetrics ): Unit = { val executionSpan = execution.context.get(Span.Key) @@ -156,7 +156,7 @@ object OnSetAdvice { currentHost.nodeMonitor.executionComplete() - //In order to correlate paging requests with initial one, carry context with message + // In order to correlate paging requests with initial one, carry context with message response.asInstanceOf[HasContext].setContext(execution.context) executionSpan.finish() } @@ -170,10 +170,10 @@ object OnExceptionAdvice { @Advice.OnMethodEnter @static def onException( - @Advice.This execution: HasContext, - @Advice.Argument(0) connection: Connection, - @Advice.Argument(1) exception: Exception, - @Advice.FieldValue("current") currentHost: Host with HasPoolMetrics + @Advice.This execution: HasContext, + @Advice.Argument(0) connection: Connection, + @Advice.Argument(1) exception: Exception, + @Advice.FieldValue("current") currentHost: Host with HasPoolMetrics ): Unit = { currentHost.nodeMonitor.clientError() @@ -193,9 +193,9 @@ object OnTimeoutAdvice { @Advice.OnMethodEnter @static def onTimeout( - @Advice.This execution: HasContext, - @Advice.Argument(0) connection: Connection, - @Advice.FieldValue("current") currentHost: Host with HasPoolMetrics + @Advice.This execution: HasContext, + @Advice.Argument(0) connection: Connection, + @Advice.FieldValue("current") currentHost: Host with HasPoolMetrics ): Unit = { currentHost.nodeMonitor.timeout() @@ -212,11 +212,11 @@ object HostLocationAdvice { @Advice.OnMethodExit @static def onHostLocationUpdate( - @Advice.This host: Host with HasPoolMetrics, - @Advice.FieldValue("manager") clusterManager: Any + @Advice.This host: Host with HasPoolMetrics, + @Advice.FieldValue("manager") clusterManager: Any ): Unit = { - val targetHost = CassandraInstrumentation.createNode(host) + val targetHost = CassandraInstrumentation.createNode(host) host.setNodeMonitor(new NodeMonitor(targetHost)) } } diff --git a/instrumentation/kamon-cassandra/src/main/scala/kamon/instrumentation/cassandra/CassandraInstrumentation.scala b/instrumentation/kamon-cassandra/src/main/scala/kamon/instrumentation/cassandra/CassandraInstrumentation.scala index a6210adf1..fdeb5f9a0 100644 --- a/instrumentation/kamon-cassandra/src/main/scala/kamon/instrumentation/cassandra/CassandraInstrumentation.scala +++ b/instrumentation/kamon-cassandra/src/main/scala/kamon/instrumentation/cassandra/CassandraInstrumentation.scala @@ -44,33 +44,33 @@ object CassandraInstrumentation { val createRoundTripSpans = enableTracing && cassandraConfig.getBoolean("tracing.create-round-trip-spans") Settings( - sampleInterval = cassandraConfig.getDuration("metrics.sample-interval"), + sampleInterval = cassandraConfig.getDuration("metrics.sample-interval"), trackNodeConnectionPoolMetrics = cassandraConfig.getBoolean("metrics.track-node-connection-pools"), - nodeTagMode = TagMode.from(cassandraConfig.getString("tracing.tags.node")), - rackTagMode = TagMode.from(cassandraConfig.getString("tracing.tags.rack")), - dcTagMode = TagMode.from(cassandraConfig.getString("tracing.tags.dc")), - enableTracing = enableTracing, - createRoundTripSpans = createRoundTripSpans + nodeTagMode = TagMode.from(cassandraConfig.getString("tracing.tags.node")), + rackTagMode = TagMode.from(cassandraConfig.getString("tracing.tags.rack")), + dcTagMode = TagMode.from(cassandraConfig.getString("tracing.tags.dc")), + enableTracing = enableTracing, + createRoundTripSpans = createRoundTripSpans ) } case class Node(address: String, dc: String, rack: String) case class Settings( - sampleInterval: Duration, - trackNodeConnectionPoolMetrics: Boolean, - nodeTagMode: TagMode, - rackTagMode: TagMode, - dcTagMode: TagMode, - enableTracing: Boolean, - createRoundTripSpans: Boolean + sampleInterval: Duration, + trackNodeConnectionPoolMetrics: Boolean, + nodeTagMode: TagMode, + rackTagMode: TagMode, + dcTagMode: TagMode, + enableTracing: Boolean, + createRoundTripSpans: Boolean ) object Tags { - val ErrorSource = "source" - val DC = "cassandra.dc" - val Node = "cassandra.node" - val Rack = "cassandra.rack" + val ErrorSource = "source" + val DC = "cassandra.dc" + val Node = "cassandra.node" + val Rack = "cassandra.rack" val CassandraDriverComponent = "cassandra.driver" } } diff --git a/instrumentation/kamon-cassandra/src/main/scala/kamon/instrumentation/cassandra/NodeConnectionPoolMetrics.scala b/instrumentation/kamon-cassandra/src/main/scala/kamon/instrumentation/cassandra/NodeConnectionPoolMetrics.scala index a02df0d02..5251a4d65 100644 --- a/instrumentation/kamon-cassandra/src/main/scala/kamon/instrumentation/cassandra/NodeConnectionPoolMetrics.scala +++ b/instrumentation/kamon-cassandra/src/main/scala/kamon/instrumentation/cassandra/NodeConnectionPoolMetrics.scala @@ -26,57 +26,57 @@ object NodeConnectionPoolMetrics { private val NodePoolPrefix = "cassandra.driver.node.pool." val BorrowTime = Kamon.timer( - name = NodePoolPrefix + "borrow-time", + name = NodePoolPrefix + "borrow-time", description = "Time spent acquiring connection to the node" ) val OpenConnections = Kamon.rangeSampler( - name = NodePoolPrefix + "connections.open", + name = NodePoolPrefix + "connections.open", description = "Tracks the number of open connections to a node" ) val InFlight = Kamon.histogram( - name = NodePoolPrefix + "in-flight", + name = NodePoolPrefix + "in-flight", description = "Tracks the Number of in-flight request sent to a node" ) val Errors = Kamon.counter( - name = NodePoolPrefix + "errors", + name = NodePoolPrefix + "errors", description = "Counts the number of failed executions" ) val Timeouts = Kamon.counter( - name = NodePoolPrefix + "timeouts", + name = NodePoolPrefix + "timeouts", description = "Counts the Number of timed-out executions" ) val Cancelled = Kamon.counter( - name = NodePoolPrefix + "cancelled", + name = NodePoolPrefix + "cancelled", description = "Counts the number of cancelled executions" ) val TriggeredSpeculations = Kamon.counter( - name = NodePoolPrefix + "retries", + name = NodePoolPrefix + "retries", description = "Counts the number of retried executions" ) class NodeConnectionPoolInstruments(node: Node) extends InstrumentGroup(createNodeTags(node)) { - val borrow: Timer = register(BorrowTime) - val openConnections: RangeSampler = register(OpenConnections) - val inFlight: Histogram = register(InFlight) - val clientErrors: Counter = register(Errors, Tags.ErrorSource, "client") - val serverErrors: Counter = register(Errors, Tags.ErrorSource, "server") - val timeouts: Counter = register(Timeouts) - val canceled: Counter = register(Cancelled) - val triggeredSpeculations: Counter = register(TriggeredSpeculations) + val borrow: Timer = register(BorrowTime) + val openConnections: RangeSampler = register(OpenConnections) + val inFlight: Histogram = register(InFlight) + val clientErrors: Counter = register(Errors, Tags.ErrorSource, "client") + val serverErrors: Counter = register(Errors, Tags.ErrorSource, "server") + val timeouts: Counter = register(Timeouts) + val canceled: Counter = register(Cancelled) + val triggeredSpeculations: Counter = register(TriggeredSpeculations) } private def createNodeTags(node: Node): TagSet = TagSet.from( Map( - Tags.DC -> node.dc, - Tags.Rack -> node.rack, - Tags.Node -> node.address + Tags.DC -> node.dc, + Tags.Rack -> node.rack, + Tags.Node -> node.address ) ) diff --git a/instrumentation/kamon-cassandra/src/main/scala/kamon/instrumentation/cassandra/SessionMetrics.scala b/instrumentation/kamon-cassandra/src/main/scala/kamon/instrumentation/cassandra/SessionMetrics.scala index dfd40569c..7eadfacfe 100644 --- a/instrumentation/kamon-cassandra/src/main/scala/kamon/instrumentation/cassandra/SessionMetrics.scala +++ b/instrumentation/kamon-cassandra/src/main/scala/kamon/instrumentation/cassandra/SessionMetrics.scala @@ -25,60 +25,60 @@ object SessionMetrics { private val sessionPrefix = "cassandra.driver.session." val BorrowTime = Kamon.timer( - name = sessionPrefix + "borrow-time", + name = sessionPrefix + "borrow-time", description = "Time spent acquiring connection from the node pool" ) val OpenConnections = Kamon.rangeSampler( - name = sessionPrefix + "connections.open", + name = sessionPrefix + "connections.open", description = "Tracks the number of open connections to all Cassandra nodes" ) val TrashedConnections = Kamon.counter( - name = sessionPrefix + "connections.trashed", + name = sessionPrefix + "connections.trashed", description = "Counts the number of trashed connections" ) val InFlight = Kamon.rangeSampler( - name = sessionPrefix + "in-flight", + name = sessionPrefix + "in-flight", description = "Tracks the number of in-flight requests sent to Cassandra" ) val Speculations = Kamon.counter( - name = sessionPrefix + "speculative-executions", + name = sessionPrefix + "speculative-executions", description = "Counts the number of speculative executions performed" ) val Retries = Kamon.counter( - name = sessionPrefix + "retries", + name = sessionPrefix + "retries", description = "Counts the number of retried executions" ) val Errors = Kamon.counter( - name = sessionPrefix + "errors", + name = sessionPrefix + "errors", description = "Counts the number of failed executions" ) val Timeouts = Kamon.counter( - name = sessionPrefix + "timeouts", + name = sessionPrefix + "timeouts", description = "Counts the number of timed-out executions" ) val Cancelled = Kamon.counter( - name = sessionPrefix + "cancelled", + name = sessionPrefix + "cancelled", description = "Counts the number of cancelled executions" ) class SessionInstruments extends InstrumentGroup(TagSet.Empty) { - val trashedConnections: Counter = register(TrashedConnections) - val borrow: Timer = register(BorrowTime) - val openConnections: RangeSampler = register(OpenConnections) - val inFlightRequests: RangeSampler = register(InFlight) - val speculations: Counter = register(Speculations) - val retries: Counter = register(Retries) - val clientErrors: Counter = register(Errors, Tags.ErrorSource, "client") - val serverErrors: Counter = register(Errors, Tags.ErrorSource, "server") - val timeouts: Counter = register(Timeouts) - val canceled: Counter = register(Cancelled) + val trashedConnections: Counter = register(TrashedConnections) + val borrow: Timer = register(BorrowTime) + val openConnections: RangeSampler = register(OpenConnections) + val inFlightRequests: RangeSampler = register(InFlight) + val speculations: Counter = register(Speculations) + val retries: Counter = register(Retries) + val clientErrors: Counter = register(Errors, Tags.ErrorSource, "client") + val serverErrors: Counter = register(Errors, Tags.ErrorSource, "server") + val timeouts: Counter = register(Timeouts) + val canceled: Counter = register(Cancelled) } } diff --git a/instrumentation/kamon-cassandra/src/main/scala/kamon/instrumentation/cassandra/driver/DriverInstrumentation.scala b/instrumentation/kamon-cassandra/src/main/scala/kamon/instrumentation/cassandra/driver/DriverInstrumentation.scala index e59e1c8c8..787ad3713 100644 --- a/instrumentation/kamon-cassandra/src/main/scala/kamon/instrumentation/cassandra/driver/DriverInstrumentation.scala +++ b/instrumentation/kamon-cassandra/src/main/scala/kamon/instrumentation/cassandra/driver/DriverInstrumentation.scala @@ -97,13 +97,13 @@ class DriverInstrumentation extends InstrumentationBuilder { .mixin(classOf[HasPoolMetrics.Mixin]) .advise(method("setLocationInfo"), classOf[HostLocationAdvice]) - /** * Cassandra Driver 4.10 support */ onTypes( - "com.datastax.oss.driver.internal.core.cql.CqlPrepareHandler", - "com.datastax.oss.driver.internal.core.cql.CqlRequestHandler") + "com.datastax.oss.driver.internal.core.cql.CqlPrepareHandler", + "com.datastax.oss.driver.internal.core.cql.CqlRequestHandler" + ) .mixin(classOf[HasContext.Mixin]) .advise(isConstructor(), classOf[OnRequestHandlerConstructorAdvice]) .advise(method("onThrottleReady"), classOf[OnThrottleReadyAdvice]) @@ -123,10 +123,10 @@ object OnRequestHandlerConstructorAdvice { @Advice.OnMethodExit() @static def exit(@Advice.This requestHandler: HasContext, @Advice.Argument(0) req: Any): Unit = { val (operationName, statement) = req match { - case pr: PrepareRequest => (QueryOperations.QueryPrepareOperationName, pr.getQuery()) + case pr: PrepareRequest => (QueryOperations.QueryPrepareOperationName, pr.getQuery()) case ss: cql.SimpleStatement => (QueryOperations.QueryOperationName, ss.getQuery()) - case bs: cql.BoundStatement => (QueryOperations.QueryOperationName, bs.getPreparedStatement.getQuery()) - case bs: cql.BatchStatement => (QueryOperations.BatchOperationName, "") + case bs: cql.BoundStatement => (QueryOperations.QueryOperationName, bs.getPreparedStatement.getQuery()) + case bs: cql.BatchStatement => (QueryOperations.BatchOperationName, "") } // Make that every case added to the "onTypes" clause for the Cassandra 4.x support @@ -147,12 +147,11 @@ object OnRequestHandlerConstructorAdvice { */ resultStage.whenComplete(new BiConsumer[Any, Throwable] { override def accept(result: Any, error: Throwable): Unit = { - if(error != null) { + if (error != null) { clientSpan .fail(error) .finish() - } - else { + } else { clientSpan.finish() } } diff --git a/instrumentation/kamon-cassandra/src/main/scala/kamon/instrumentation/cassandra/driver/InstrumentedSession.scala b/instrumentation/kamon-cassandra/src/main/scala/kamon/instrumentation/cassandra/driver/InstrumentedSession.scala index 8c91db0e4..caa7cda4b 100644 --- a/instrumentation/kamon-cassandra/src/main/scala/kamon/instrumentation/cassandra/driver/InstrumentedSession.scala +++ b/instrumentation/kamon-cassandra/src/main/scala/kamon/instrumentation/cassandra/driver/InstrumentedSession.scala @@ -21,7 +21,13 @@ import java.util import com.datastax.driver.core._ import com.google.common.base.Function -import com.google.common.util.concurrent.{FutureCallback, Futures, ListenableFuture, ListeningExecutorService, MoreExecutors} +import com.google.common.util.concurrent.{ + FutureCallback, + Futures, + ListenableFuture, + ListeningExecutorService, + MoreExecutors +} import kamon.Kamon import kamon.instrumentation.cassandra.CassandraInstrumentation import kamon.trace.Span @@ -41,15 +47,19 @@ class InstrumentedSession(underlying: Session) extends AbstractSession { new InstrumentedSession(underlying.init()) override def initAsync(): ListenableFuture[Session] = { - Futures.transform(underlying.initAsync(), new Function[Session, Session] { - override def apply(session: Session): Session = - new InstrumentedSession(session) - }, executor) + Futures.transform( + underlying.initAsync(), + new Function[Session, Session] { + override def apply(session: Session): Session = + new InstrumentedSession(session) + }, + executor + ) } override def prepareAsync( - query: String, - customPayload: util.Map[String, ByteBuffer] + query: String, + customPayload: util.Map[String, ByteBuffer] ): ListenableFuture[PreparedStatement] = { val statement = new SimpleStatement(query) statement.setOutgoingPayload(customPayload) @@ -57,8 +67,8 @@ class InstrumentedSession(underlying: Session) extends AbstractSession { } private def buildClientSpan(statement: Statement): Span = - if(CassandraInstrumentation.settings.enableTracing) { - val query = extractQuery(statement) + if (CassandraInstrumentation.settings.enableTracing) { + val query = extractQuery(statement) val statementKind = extractStatementType(query) val clientSpan = Kamon @@ -108,7 +118,7 @@ class InstrumentedSession(underlying: Session) extends AbstractSession { } private def recordClientQueryExecutionInfo(clientSpan: Span, result: ResultSet): Unit = { - val info = result.getExecutionInfo + val info = result.getExecutionInfo val hasMore = !result.isFullyFetched val trace = info.getQueryTrace diff --git a/instrumentation/kamon-cassandra/src/main/scala/kamon/instrumentation/cassandra/executors/ExecutorInstrumentation.scala b/instrumentation/kamon-cassandra/src/main/scala/kamon/instrumentation/cassandra/executors/ExecutorInstrumentation.scala index 9d2552533..50e80c02f 100644 --- a/instrumentation/kamon-cassandra/src/main/scala/kamon/instrumentation/cassandra/executors/ExecutorInstrumentation.scala +++ b/instrumentation/kamon-cassandra/src/main/scala/kamon/instrumentation/cassandra/executors/ExecutorInstrumentation.scala @@ -67,7 +67,7 @@ object CreateBlockingTasksExecutorAdvice extends ExecutorMetrics { class CreateReaperExecutorAdvice object CreateReaperExecutorAdvice extends ExecutorMetrics { @static def onExecutorCreated( - @SuperCall callable: Callable[ScheduledExecutorService] + @SuperCall callable: Callable[ScheduledExecutorService] ): ScheduledExecutorService = instrumentScheduled(callable, "reaper") } @@ -75,7 +75,7 @@ object CreateReaperExecutorAdvice extends ExecutorMetrics { class CreateScheduledTasksExecutorAdvice object CreateScheduledTasksExecutorAdvice extends ExecutorMetrics { @static def onExecutorCreated( - @SuperCall callable: Callable[ScheduledExecutorService] + @SuperCall callable: Callable[ScheduledExecutorService] ): ScheduledExecutorService = instrumentScheduled(callable, "scheduled-tasks") } @@ -83,7 +83,7 @@ object CreateScheduledTasksExecutorAdvice extends ExecutorMetrics { class CreateReconnectionExecutorAdvice object CreateReconnectionExecutorAdvice extends ExecutorMetrics { @static def onExecutorCreated( - @SuperCall callable: Callable[ScheduledExecutorService] + @SuperCall callable: Callable[ScheduledExecutorService] ): ScheduledExecutorService = instrumentScheduled(callable, "reconnection") } diff --git a/instrumentation/kamon-cassandra/src/main/scala/kamon/instrumentation/cassandra/metrics/NodeMonitor.scala b/instrumentation/kamon-cassandra/src/main/scala/kamon/instrumentation/cassandra/metrics/NodeMonitor.scala index 0ffa99717..2eb531a37 100644 --- a/instrumentation/kamon-cassandra/src/main/scala/kamon/instrumentation/cassandra/metrics/NodeMonitor.scala +++ b/instrumentation/kamon-cassandra/src/main/scala/kamon/instrumentation/cassandra/metrics/NodeMonitor.scala @@ -98,7 +98,7 @@ class NodeMonitor(node: Node) { } def cleanup(): Unit = { - if(poolMetrics != null) + if (poolMetrics != null) poolMetrics.remove() } } diff --git a/instrumentation/kamon-cats-io-3/src/main/scala/kamon/instrumentation/cats3/IOFiberInstrumentation.scala b/instrumentation/kamon-cats-io-3/src/main/scala/kamon/instrumentation/cats3/IOFiberInstrumentation.scala index 92ef24295..b97156216 100644 --- a/instrumentation/kamon-cats-io-3/src/main/scala/kamon/instrumentation/cats3/IOFiberInstrumentation.scala +++ b/instrumentation/kamon-cats-io-3/src/main/scala/kamon/instrumentation/cats3/IOFiberInstrumentation.scala @@ -17,24 +17,28 @@ class IOFiberInstrumentation extends InstrumentationBuilder { .advise(method("resume"), RestoreContextOnSuccessfulResume) .advise(method("run"), RunLoopWithContext) - // We must save the context on calls to `schedule*`/`reschedule*` because the Fiber // might start executing on another thread before the call to `run` on the current // thread terminates. onTypes("cats.effect.IOFiber") - .advise(anyMethods( - "rescheduleFiber", - "scheduleFiber", - "scheduleOnForeignEC", - ), SetContextOnNewFiber) + .advise( + anyMethods( + "rescheduleFiber", + "scheduleFiber", + "scheduleOnForeignEC" + ), + SetContextOnNewFiber + ) onTypes("cats.effect.unsafe.WorkStealingThreadPool") - .advise(anyMethods( - "scheduleFiber", - "rescheduleFiber", - "scheduleExternal" - ), SetContextOnNewFiberForWSTP) - + .advise( + anyMethods( + "scheduleFiber", + "rescheduleFiber", + "scheduleExternal" + ), + SetContextOnNewFiberForWSTP + ) // Scheduled actions like `IO.sleep` end up calling `resume` from the scheduler thread, // which always leaves a dirty thread. This wrapper ensures that scheduled actions are @@ -48,7 +52,7 @@ class AfterFiberInit object AfterFiberInit { @Advice.OnMethodExit - @static def exit(@Advice.This fiber: Any): Unit ={ + @static def exit(@Advice.This fiber: Any): Unit = { fiber.asInstanceOf[HasContext].setContext(Kamon.currentContext()) } } @@ -76,7 +80,7 @@ object RestoreContextOnSuccessfulResume { @Advice.OnMethodExit() @static def exit(@Advice.This fiber: Any, @Advice.Return wasSuspended: Boolean): Unit = { - if(wasSuspended) { + if (wasSuspended) { val ctxFiber = fiber.asInstanceOf[HasContext].context Kamon.storeContext(ctxFiber) } diff --git a/instrumentation/kamon-cats-io-3/src/test/scala/kamon/instrumentation/futures/cats3/CatsIoInstrumentationSpec.scala b/instrumentation/kamon-cats-io-3/src/test/scala/kamon/instrumentation/futures/cats3/CatsIoInstrumentationSpec.scala index a158e1755..85a8bfcd6 100644 --- a/instrumentation/kamon-cats-io-3/src/test/scala/kamon/instrumentation/futures/cats3/CatsIoInstrumentationSpec.scala +++ b/instrumentation/kamon-cats-io-3/src/test/scala/kamon/instrumentation/futures/cats3/CatsIoInstrumentationSpec.scala @@ -28,10 +28,10 @@ class CatsIoInstrumentationSpec extends AnyWordSpec with Matchers with ScalaFutu "must capture the current context when creating and running fibers" in { val runtime = IORuntime.global - val anotherExecutionContext: ExecutionContext = ExecutionContext.fromExecutorService(Executors.newFixedThreadPool(10)) + val anotherExecutionContext: ExecutionContext = + ExecutionContext.fromExecutorService(Executors.newFixedThreadPool(10)) val context = Context.of("tool", "kamon") - val effect = for { contextOnAnotherThread <- IO.delay(Kamon.currentContext()) _ <- IO.delay(Seq("hello", "world")) @@ -60,7 +60,8 @@ class CatsIoInstrumentationSpec extends AnyWordSpec with Matchers with ScalaFutu "must allow the context to be cleaned" in { val runtime = IORuntime.global - val anotherExecutionContext: ExecutionContext = ExecutionContext.fromExecutorService(Executors.newFixedThreadPool(10)) + val anotherExecutionContext: ExecutionContext = + ExecutionContext.fromExecutorService(Executors.newFixedThreadPool(10)) val context = Context.of("key", "value") val test = @@ -81,13 +82,14 @@ class CatsIoInstrumentationSpec extends AnyWordSpec with Matchers with ScalaFutu "must be available across asynchronous boundaries" in { val runtime = IORuntime.apply( - ExecutionContext.fromExecutor(Executors.newFixedThreadPool(1)), //pool 4 + ExecutionContext.fromExecutor(Executors.newFixedThreadPool(1)), // pool 4 ExecutionContext.fromExecutor(Executors.newFixedThreadPool(1)), // pool 5 - Scheduler.fromScheduledExecutor(Executors.newSingleThreadScheduledExecutor()), //pool 6 + Scheduler.fromScheduledExecutor(Executors.newSingleThreadScheduledExecutor()), // pool 6 () => (), IORuntimeConfig.apply() ) - val anotherExecutionContext: ExecutionContext = ExecutionContext.fromExecutorService(Executors.newFixedThreadPool(1)) //pool 7 + val anotherExecutionContext: ExecutionContext = + ExecutionContext.fromExecutorService(Executors.newFixedThreadPool(1)) // pool 7 val context = Context.of("key", "value") val test = for { @@ -117,7 +119,7 @@ class CatsIoInstrumentationSpec extends AnyWordSpec with Matchers with ScalaFutu test.unsafeRunSync()(runtime) } - "must allow complex Span topologies to be created" in { + "must allow complex Span topologies to be created" in { val parentSpan = Span.Remote( Scheme.Single.spanIdFactory.generate(), Identifier.Empty, @@ -125,6 +127,7 @@ class CatsIoInstrumentationSpec extends AnyWordSpec with Matchers with ScalaFutu ) val context = Context.of(Span.Key, parentSpan) implicit val ec = ExecutionContext.global + /** * test * - nestedLevel0 @@ -135,8 +138,10 @@ class CatsIoInstrumentationSpec extends AnyWordSpec with Matchers with ScalaFutu val test = for { span <- IO.delay(Kamon.currentSpan()) nestedLevel0 <- meteredWithSpanCapture("level1-A")(IO.sleep(100.millis)) - nestedUpToLevel2 <- meteredWithSpanCapture("level1-B")(meteredWithSpanCapture("level2-B")(IO.sleep(100.millis))) - fiftyInParallel <- (0 to 49).toList.parTraverse(i => meteredWithSpanCapture(s"operation$i")(IO.sleep(100.millis))) + nestedUpToLevel2 <- + meteredWithSpanCapture("level1-B")(meteredWithSpanCapture("level2-B")(IO.sleep(100.millis))) + fiftyInParallel <- + (0 to 49).toList.parTraverse(i => meteredWithSpanCapture(s"operation$i")(IO.sleep(100.millis))) afterCede <- meteredWithSpanCapture("cede")(IO.cede *> IO.delay(Kamon.currentSpan())) afterEverything <- IO.delay(Kamon.currentSpan()) } yield { @@ -146,13 +151,15 @@ class CatsIoInstrumentationSpec extends AnyWordSpec with Matchers with ScalaFutu nestedUpToLevel2._1.id.string shouldBe nestedUpToLevel2._2._1.parentId.string fiftyInParallel.map(_._1.parentId.string).toSet shouldBe Set(span.id.string) fiftyInParallel.map(_._1.id.string).toSet should have size 50 - afterCede._1.id.string shouldBe afterCede._2.id.string //A cede should not cause the span to be lost + afterCede._1.id.string shouldBe afterCede._2.id.string // A cede should not cause the span to be lost afterEverything.id.string shouldBe span.id.string } val runtime = IORuntime.global val result = scala.concurrent.Future.sequence( - (1 to 100).toList.map(_ => (IO.delay(Kamon.init()) *> IO.delay(Kamon.storeContext(context)) *> test).unsafeToFuture()(runtime)) + (1 to 100).toList.map(_ => + (IO.delay(Kamon.init()) *> IO.delay(Kamon.storeContext(context)) *> test).unsafeToFuture()(runtime) + ) ) Await.result(result, 100.seconds) } @@ -170,20 +177,20 @@ class CatsIoInstrumentationSpec extends AnyWordSpec with Matchers with ScalaFutu } private def meteredWithSpanCapture[A](operation: String)(io: IO[A]): IO[(Span, A)] = { - Resource.make{ + Resource.make { + for { + initialCtx <- IO(Kamon.currentContext()) + parentSpan <- IO(Kamon.currentSpan()) + newSpan <- IO(Kamon.spanBuilder(operation).context(initialCtx).asChildOf(parentSpan).start()) + _ <- IO(Kamon.storeContext(initialCtx.withEntry(Span.Key, newSpan))) + } yield (initialCtx, newSpan) + } { + case (initialCtx, span) => for { - initialCtx <- IO(Kamon.currentContext()) - parentSpan <- IO(Kamon.currentSpan()) - newSpan <- IO(Kamon.spanBuilder(operation).context(initialCtx).asChildOf(parentSpan).start()) - _ <- IO(Kamon.storeContext(initialCtx.withEntry(Span.Key, newSpan))) - } yield (initialCtx, newSpan) - }{ - case (initialCtx, span) => - for { - _ <- IO.delay(span.finish()) - _ <- IO.delay(Kamon.storeContext(initialCtx)) - } yield () - } + _ <- IO.delay(span.finish()) + _ <- IO.delay(Kamon.storeContext(initialCtx)) + } yield () + } .use(_ => (IO.delay(Kamon.currentSpan()), io).parBisequence) } -} \ No newline at end of file +} diff --git a/instrumentation/kamon-cats-io/src/test/scala/kamon/instrumentation/futures/cats/CatsIOInstrumentationSpec.scala b/instrumentation/kamon-cats-io/src/test/scala/kamon/instrumentation/futures/cats/CatsIOInstrumentationSpec.scala index d8298338f..5ae7fed11 100644 --- a/instrumentation/kamon-cats-io/src/test/scala/kamon/instrumentation/futures/cats/CatsIOInstrumentationSpec.scala +++ b/instrumentation/kamon-cats-io/src/test/scala/kamon/instrumentation/futures/cats/CatsIOInstrumentationSpec.scala @@ -50,11 +50,10 @@ class CatsIoInstrumentationSpec extends AnyWordSpec with Matchers with ScalaFutu val contextTagFuture = contextTagAfterTransformations.unsafeToFuture() - eventually(timeout(10 seconds)) { contextTagFuture.value.get.get shouldBe "value" } } } } -} \ No newline at end of file +} diff --git a/instrumentation/kamon-elasticsearch/src/main/scala/kamon/instrumentation/elasticsearch/ESInstrumentation.scala b/instrumentation/kamon-elasticsearch/src/main/scala/kamon/instrumentation/elasticsearch/ESInstrumentation.scala index d9ba86ebc..d6dbd2d95 100644 --- a/instrumentation/kamon-elasticsearch/src/main/scala/kamon/instrumentation/elasticsearch/ESInstrumentation.scala +++ b/instrumentation/kamon-elasticsearch/src/main/scala/kamon/instrumentation/elasticsearch/ESInstrumentation.scala @@ -28,8 +28,14 @@ class ESInstrumentation extends InstrumentationBuilder { .advise(method("performRequest").and(takesArguments(1)), classOf[SyncElasticsearchRestClientInstrumentation]) onType("org.elasticsearch.client.RestHighLevelClient") - .advise(method("internalPerformRequest").and(takesArguments(5)), classOf[HighLevelElasticsearchClientInstrumentation]) - .advise(method("internalPerformRequestAsync").and(takesArguments(6)), classOf[HighLevelElasticsearchClientInstrumentation]) + .advise( + method("internalPerformRequest").and(takesArguments(5)), + classOf[HighLevelElasticsearchClientInstrumentation] + ) + .advise( + method("internalPerformRequestAsync").and(takesArguments(6)), + classOf[HighLevelElasticsearchClientInstrumentation] + ) } class InstrumentedListener(inner: ResponseListener, span: Span) extends ResponseListener { diff --git a/instrumentation/kamon-elasticsearch/src/test/scala/kamon/instrumentation/ElasticSearchInstrumentationTest.scala b/instrumentation/kamon-elasticsearch/src/test/scala/kamon/instrumentation/ElasticSearchInstrumentationTest.scala index 462ce6138..233132967 100644 --- a/instrumentation/kamon-elasticsearch/src/test/scala/kamon/instrumentation/ElasticSearchInstrumentationTest.scala +++ b/instrumentation/kamon-elasticsearch/src/test/scala/kamon/instrumentation/ElasticSearchInstrumentationTest.scala @@ -13,9 +13,8 @@ import org.scalatest.time.SpanSugar import org.scalatest.wordspec.AnyWordSpec import org.scalatest.OptionValues - class ElasticSearchInstrumentationTest - extends AnyWordSpec + extends AnyWordSpec with Matchers with Eventually with SpanSugar @@ -41,11 +40,13 @@ class ElasticSearchInstrumentationTest } "records a span for a basic async request" in { - client.performRequestAsync(new Request("GET", "/_cluster/health"), + client.performRequestAsync( + new Request("GET", "/_cluster/health"), new ResponseListener() { override def onSuccess(response: Response): Unit = () override def onFailure(exception: Exception): Unit = () - }) + } + ) eventually(timeout(5 seconds)) { val span = testSpanReporter().nextSpan().value @@ -84,7 +85,6 @@ class ElasticSearchInstrumentationTest } } - override val container: ElasticsearchContainer = ElasticsearchContainer() var client: RestClient = _ var highLevelClient: RestHighLevelClient = _ @@ -98,7 +98,8 @@ class ElasticSearchInstrumentationTest .build() highLevelClient = new RestHighLevelClient( - RestClient.builder(HttpHost.create(container.httpHostAddress))) + RestClient.builder(HttpHost.create(container.httpHostAddress)) + ) } override protected def afterAll(): Unit = { diff --git a/instrumentation/kamon-executors-bench/src/main/scala/kamon/instrumentation/bench/ExecutorInstrumentationBenchmark.scala b/instrumentation/kamon-executors-bench/src/main/scala/kamon/instrumentation/bench/ExecutorInstrumentationBenchmark.scala index a5f2790a5..0aa7b96f3 100644 --- a/instrumentation/kamon-executors-bench/src/main/scala/kamon/instrumentation/bench/ExecutorInstrumentationBenchmark.scala +++ b/instrumentation/kamon-executors-bench/src/main/scala/kamon/instrumentation/bench/ExecutorInstrumentationBenchmark.scala @@ -37,7 +37,7 @@ class ExecutorInstrumentationBenchmark { @Fork def control(blackhole: Blackhole): Unit = { MoreExecutors.directExecutor.execute(new BlackholeRunnable(blackhole)) - } + } /** * This benchmark attempts to measure the performance with manual context propagation. diff --git a/instrumentation/kamon-executors/src/main/scala-2.12/kamon/instrumentation/package.scala b/instrumentation/kamon-executors/src/main/scala-2.12/kamon/instrumentation/package.scala index d8465589a..c5fb17593 100644 --- a/instrumentation/kamon-executors/src/main/scala-2.12/kamon/instrumentation/package.scala +++ b/instrumentation/kamon-executors/src/main/scala-2.12/kamon/instrumentation/package.scala @@ -16,5 +16,5 @@ package kamon.instrumentation package object executor { - type ScalaForkJoinPool = java.util.concurrent.ForkJoinPool + type ScalaForkJoinPool = java.util.concurrent.ForkJoinPool } diff --git a/instrumentation/kamon-executors/src/main/scala/kamon/instrumentation/executor/ExecutorInstrumentation.scala b/instrumentation/kamon-executors/src/main/scala/kamon/instrumentation/executor/ExecutorInstrumentation.scala index 374049e20..82e80ecc7 100644 --- a/instrumentation/kamon-executors/src/main/scala/kamon/instrumentation/executor/ExecutorInstrumentation.scala +++ b/instrumentation/kamon-executors/src/main/scala/kamon/instrumentation/executor/ExecutorInstrumentation.scala @@ -18,7 +18,17 @@ package kamon.instrumentation.executor import java.time.Duration import java.util -import java.util.concurrent.{Callable, ExecutorService, Future, ScheduledExecutorService, ScheduledFuture, ScheduledThreadPoolExecutor, ThreadPoolExecutor, TimeUnit, ForkJoinPool => JavaForkJoinPool} +import java.util.concurrent.{ + Callable, + ExecutorService, + Future, + ScheduledExecutorService, + ScheduledFuture, + ScheduledThreadPoolExecutor, + ThreadPoolExecutor, + TimeUnit, + ForkJoinPool => JavaForkJoinPool +} import com.typesafe.config.Config import kamon.Kamon import kamon.jsr166.LongAdder @@ -103,7 +113,11 @@ object ExecutorInstrumentation { * * Once the returned executor is shutdown, all related metric instruments will be removed. */ - def instrumentExecutionContext(executionContext: ExecutionContext, name: String, settings: Settings): InstrumentedExecutionContext = + def instrumentExecutionContext( + executionContext: ExecutionContext, + name: String, + settings: Settings + ): InstrumentedExecutionContext = instrumentExecutionContext(executionContext, name, TagSet.Empty, name, settings) /** @@ -131,7 +145,11 @@ object ExecutorInstrumentation { * * Once the returned executor is shutdown, all related metric instruments will be removed. */ - def instrumentExecutionContext(executionContext: ExecutionContext, name: String, extraTags: TagSet): InstrumentedExecutionContext = + def instrumentExecutionContext( + executionContext: ExecutionContext, + name: String, + extraTags: TagSet + ): InstrumentedExecutionContext = instrumentExecutionContext(executionContext, name, extraTags, name, DefaultSettings) /** @@ -161,11 +179,31 @@ object ExecutorInstrumentation { * * Once the returned executor is shutdown, all related metric instruments will be removed. */ - def instrument(executor: ExecutorService, name: String, extraTags: TagSet, scheduledActionName: String, settings: Settings): ExecutorService = { + def instrument( + executor: ExecutorService, + name: String, + extraTags: TagSet, + scheduledActionName: String, + settings: Settings + ): ExecutorService = { executor match { - case tpe: ThreadPoolExecutor => new InstrumentedThreadPool(tpe, name, extraTags, scheduledActionName, settings) - case jfjp: JavaForkJoinPool => new InstrumentedForkJoinPool(jfjp, ForkJoinPoolTelemetryReader.forJava(jfjp), name, extraTags, scheduledActionName, settings) - case sfjp: ScalaForkJoinPool => new InstrumentedForkJoinPool(sfjp, ForkJoinPoolTelemetryReader.forScala(sfjp), name, extraTags, scheduledActionName, settings) + case tpe: ThreadPoolExecutor => new InstrumentedThreadPool(tpe, name, extraTags, scheduledActionName, settings) + case jfjp: JavaForkJoinPool => new InstrumentedForkJoinPool( + jfjp, + ForkJoinPoolTelemetryReader.forJava(jfjp), + name, + extraTags, + scheduledActionName, + settings + ) + case sfjp: ScalaForkJoinPool => new InstrumentedForkJoinPool( + sfjp, + ForkJoinPoolTelemetryReader.forScala(sfjp), + name, + extraTags, + scheduledActionName, + settings + ) case anyOther => _logger.warn("Cannot instrument unknown executor [{}]", anyOther) executor @@ -184,7 +222,11 @@ object ExecutorInstrumentation { * * Once the returned executor is shutdown, all related metric instruments will be removed. */ - def instrumentScheduledExecutor(executor: ScheduledExecutorService, name: String, extraTags: TagSet): ScheduledExecutorService = + def instrumentScheduledExecutor( + executor: ScheduledExecutorService, + name: String, + extraTags: TagSet + ): ScheduledExecutorService = instrumentScheduledExecutor(executor, name, extraTags, name) /** @@ -199,13 +241,22 @@ object ExecutorInstrumentation { * * Once the returned executor is shutdown, all related metric instruments will be removed. */ - def instrumentScheduledExecutor(executor: ScheduledExecutorService, name: String, extraTags: TagSet, - scheduledActionName: String): ScheduledExecutorService = { + def instrumentScheduledExecutor( + executor: ScheduledExecutorService, + name: String, + extraTags: TagSet, + scheduledActionName: String + ): ScheduledExecutorService = { executor match { case stpe: ScheduledThreadPoolExecutor => - new InstrumentedScheduledThreadPoolExecutor(stpe, name, extraTags.withTag("scheduled", true), scheduledActionName) + new InstrumentedScheduledThreadPoolExecutor( + stpe, + name, + extraTags.withTag("scheduled", true), + scheduledActionName + ) case anyOther => _logger.warn("Cannot instrument unknown executor [{}]", anyOther) @@ -225,8 +276,13 @@ object ExecutorInstrumentation { * * Once the returned executor is shutdown, all related metric instruments will be removed. */ - def instrumentExecutionContext(executionContext: ExecutionContext, name: String, extraTags: TagSet, scheduledActionName: String, - settings: Settings): InstrumentedExecutionContext = { + def instrumentExecutionContext( + executionContext: ExecutionContext, + name: String, + extraTags: TagSet, + scheduledActionName: String, + settings: Settings + ): InstrumentedExecutionContext = { val underlyingExecutor = unwrapExecutionContext(executionContext) .map(executor => instrument(executor, name, extraTags, scheduledActionName, settings)) @@ -246,8 +302,14 @@ object ExecutorInstrumentation { * * Once the returned executor is shutdown, all related metric instruments will be removed. */ - def instrument(executor: ExecutorService, telemetryReader: ForkJoinPoolTelemetryReader, name: String, extraTags: TagSet, - scheduledActionName: String, settings: Settings): ExecutorService = { + def instrument( + executor: ExecutorService, + telemetryReader: ForkJoinPoolTelemetryReader, + name: String, + extraTags: TagSet, + scheduledActionName: String, + settings: Settings + ): ExecutorService = { new InstrumentedForkJoinPool(executor, telemetryReader, name, extraTags, scheduledActionName, settings) } @@ -314,17 +376,17 @@ object ExecutorInstrumentation { object ForkJoinPoolTelemetryReader { def forJava(pool: JavaForkJoinPool): ForkJoinPoolTelemetryReader = new ForkJoinPoolTelemetryReader { - override def activeThreads: Int = pool.getActiveThreadCount - override def poolSize: Int = pool.getPoolSize - override def queuedTasks: Int = pool.getQueuedSubmissionCount - override def parallelism: Int = pool.getParallelism + override def activeThreads: Int = pool.getActiveThreadCount + override def poolSize: Int = pool.getPoolSize + override def queuedTasks: Int = pool.getQueuedSubmissionCount + override def parallelism: Int = pool.getParallelism } def forScala(pool: ScalaForkJoinPool): ForkJoinPoolTelemetryReader = new ForkJoinPoolTelemetryReader { - override def activeThreads: Int = pool.getActiveThreadCount - override def poolSize: Int = pool.getPoolSize - override def queuedTasks: Int = pool.getQueuedSubmissionCount - override def parallelism: Int = pool.getParallelism + override def activeThreads: Int = pool.getActiveThreadCount + override def poolSize: Int = pool.getPoolSize + override def queuedTasks: Int = pool.getQueuedSubmissionCount + override def parallelism: Int = pool.getParallelism } } @@ -342,8 +404,13 @@ object ExecutorInstrumentation { * * The instruments used to track the pool's behavior are removed once the pool is shut down. */ - class InstrumentedThreadPool(wrapped: ThreadPoolExecutor, name: String, extraTags: TagSet, scheduledActionName: String, - settings: Settings) extends ExecutorService { + class InstrumentedThreadPool( + wrapped: ThreadPoolExecutor, + name: String, + extraTags: TagSet, + scheduledActionName: String, + settings: Settings + ) extends ExecutorService { private val _runnableWrapper = buildRunnableWrapper() private val _callableWrapper = buildCallableWrapper() @@ -368,7 +435,9 @@ object ExecutorInstrumentation { override def stop(): Unit = {} override def reconfigure(newConfig: Config): Unit = {} - }, _sampleInterval) + }, + _sampleInterval + ) protected def executorType: String = "ThreadPoolExecutor" @@ -388,7 +457,11 @@ object ExecutorInstrumentation { override def invokeAll[T](tasks: java.util.Collection[_ <: Callable[T]]): java.util.List[Future[T]] = wrapped.invokeAll(wrapTasks(tasks).asInstanceOf[java.util.Collection[Callable[T]]]) - override def invokeAll[T](tasks: java.util.Collection[_ <: Callable[T]], timeout: Long, unit: TimeUnit): java.util.List[Future[T]] = + override def invokeAll[T]( + tasks: java.util.Collection[_ <: Callable[T]], + timeout: Long, + unit: TimeUnit + ): java.util.List[Future[T]] = wrapped.invokeAll(wrapTasks(tasks).asInstanceOf[java.util.Collection[Callable[T]]], timeout, unit) override def isTerminated: Boolean = @@ -421,7 +494,7 @@ object ExecutorInstrumentation { private def wrapTasks[T](tasks: java.util.Collection[_ <: Callable[T]]): java.util.Collection[_ <: Callable[T]] = { val wrappedTasks = new util.LinkedList[Callable[T]]() val iterator = tasks.iterator() - while(iterator.hasNext) { + while (iterator.hasNext) { wrappedTasks.add(_callableWrapper.wrap(iterator.next())) } @@ -429,13 +502,13 @@ object ExecutorInstrumentation { } private def buildRunnableWrapper(): Runnable => Runnable = { - if(settings.shouldTrackTimeInQueue) { + if (settings.shouldTrackTimeInQueue) { if (settings.shouldPropagateContextOnSubmit) runnable => new TimingAndContextPropagatingRunnable(runnable) else runnable => new TimingRunnable(runnable) } else { - if(settings.shouldPropagateContextOnSubmit) + if (settings.shouldPropagateContextOnSubmit) runnable => new ContextPropagationRunnable(runnable) else runnable => runnable @@ -443,7 +516,7 @@ object ExecutorInstrumentation { } private def buildCallableWrapper(): CallableWrapper = { - if(settings.shouldTrackTimeInQueue) { + if (settings.shouldTrackTimeInQueue) { if (settings.shouldPropagateContextOnSubmit) new TimingAndContextPropagatingCallableWrapper() else @@ -475,7 +548,8 @@ object ExecutorInstrumentation { _timeInQueueTimer.record(System.nanoTime() - _createdAt) val scope = Kamon.storeContext(_context) - try { runnable.run() } finally { scope.close() } + try { runnable.run() } + finally { scope.close() } } } @@ -499,7 +573,8 @@ object ExecutorInstrumentation { _timeInQueueTimer.record(System.nanoTime() - _createdAt) val scope = Kamon.storeContext(_context) - try { callable.call() } finally { scope.close() } + try { callable.call() } + finally { scope.close() } } } } @@ -520,7 +595,8 @@ object ExecutorInstrumentation { override def call(): T = { val scope = Kamon.storeContext(_context) - try { callable.call() } finally { scope.close() } + try { callable.call() } + finally { scope.close() } } } } @@ -533,8 +609,13 @@ object ExecutorInstrumentation { * * The instruments used to track the pool's behavior are removed once the pool is shut down. */ - class InstrumentedScheduledThreadPoolExecutor(wrapped: ScheduledThreadPoolExecutor, name: String, extraTags: TagSet, scheduledActionName: String) - extends InstrumentedThreadPool(wrapped, name, extraTags, scheduledActionName, NoExtraSettings) with ScheduledExecutorService { + class InstrumentedScheduledThreadPoolExecutor( + wrapped: ScheduledThreadPoolExecutor, + name: String, + extraTags: TagSet, + scheduledActionName: String + ) extends InstrumentedThreadPool(wrapped, name, extraTags, scheduledActionName, NoExtraSettings) + with ScheduledExecutorService { override protected def executorType: String = "ScheduledThreadPoolExecutor" @@ -545,14 +626,23 @@ object ExecutorInstrumentation { override def schedule[V](callable: Callable[V], delay: Long, unit: TimeUnit): ScheduledFuture[V] = wrapped.schedule(callable, delay, unit) - override def scheduleAtFixedRate(command: Runnable, initialDelay: Long, period: Long, unit: TimeUnit): ScheduledFuture[_] = + override def scheduleAtFixedRate( + command: Runnable, + initialDelay: Long, + period: Long, + unit: TimeUnit + ): ScheduledFuture[_] = wrapped.scheduleAtFixedRate(command, initialDelay, period, unit) - override def scheduleWithFixedDelay(command: Runnable, initialDelay: Long, delay: Long, unit: TimeUnit): ScheduledFuture[_] = + override def scheduleWithFixedDelay( + command: Runnable, + initialDelay: Long, + delay: Long, + unit: TimeUnit + ): ScheduledFuture[_] = wrapped.scheduleWithFixedDelay(command, initialDelay, delay, unit) } - /** * Executor service wrapper for ForkJoin Pool executors that keeps track of submitted and completed tasks and * optionally tracks the time tasks spend waiting on the underlying executor service's queue. This instrumented @@ -561,8 +651,14 @@ object ExecutorInstrumentation { * * The instruments used to track the pool's behavior are removed once the pool is shut down. */ - class InstrumentedForkJoinPool(wrapped: ExecutorService, telemetryReader: ForkJoinPoolTelemetryReader, name: String, - extraTags: TagSet, scheduledActionName: String, settings: Settings) extends ExecutorService { + class InstrumentedForkJoinPool( + wrapped: ExecutorService, + telemetryReader: ForkJoinPoolTelemetryReader, + name: String, + extraTags: TagSet, + scheduledActionName: String, + settings: Settings + ) extends ExecutorService { private val _runnableWrapper = buildRunnableWrapper() private val _callableWrapper = buildCallableWrapper() @@ -578,7 +674,7 @@ object ExecutorInstrumentation { val completedTaskCountSource = Counter.delta(() => _completedTasksCounter.longValue()) override def run(): Unit = { - _instruments.poolMin.update(0D) + _instruments.poolMin.update(0d) _instruments.poolMax.update(telemetryReader.parallelism) _instruments.parallelism.update(telemetryReader.parallelism) _instruments.totalThreads.record(telemetryReader.poolSize) @@ -591,7 +687,9 @@ object ExecutorInstrumentation { override def stop(): Unit = {} override def reconfigure(newConfig: Config): Unit = {} - }, _sampleInterval) + }, + _sampleInterval + ) override def execute(command: Runnable): Unit = { _submittedTasksCounter.increment() @@ -618,7 +716,11 @@ object ExecutorInstrumentation { wrapped.invokeAll(wrapTasks(tasks).asInstanceOf[java.util.Collection[Callable[T]]]) } - override def invokeAll[T](tasks: java.util.Collection[_ <: Callable[T]], timeout: Long, unit: TimeUnit): java.util.List[Future[T]] = { + override def invokeAll[T]( + tasks: java.util.Collection[_ <: Callable[T]], + timeout: Long, + unit: TimeUnit + ): java.util.List[Future[T]] = { _submittedTasksCounter.add(tasks.size()) wrapped.invokeAll(wrapTasks(tasks).asInstanceOf[java.util.Collection[Callable[T]]], timeout, unit) } @@ -653,7 +755,7 @@ object ExecutorInstrumentation { private def wrapTasks[T](tasks: java.util.Collection[_ <: Callable[T]]): java.util.Collection[_ <: Callable[T]] = { val wrappedTasks = new util.LinkedList[Callable[T]]() val iterator = tasks.iterator() - while(iterator.hasNext) { + while (iterator.hasNext) { wrappedTasks.add(_callableWrapper.wrap(iterator.next())) } @@ -661,13 +763,13 @@ object ExecutorInstrumentation { } private def buildRunnableWrapper(): Runnable => Runnable = { - if(settings.shouldTrackTimeInQueue) { + if (settings.shouldTrackTimeInQueue) { if (settings.shouldPropagateContextOnSubmit) runnable => new TimingAndContextPropagatingRunnable(runnable) else runnable => new TimingRunnable(runnable) } else { - if(settings.shouldPropagateContextOnSubmit) + if (settings.shouldPropagateContextOnSubmit) runnable => new ContextPropagationRunnable(runnable) else runnable => runnable @@ -675,7 +777,7 @@ object ExecutorInstrumentation { } private def buildCallableWrapper(): CallableWrapper = { - if(settings.shouldTrackTimeInQueue) { + if (settings.shouldTrackTimeInQueue) { if (settings.shouldPropagateContextOnSubmit) new TimingAndContextPropagatingCallableWrapper() else @@ -695,7 +797,8 @@ object ExecutorInstrumentation { override def run(): Unit = { _timeInQueueTimer.record(System.nanoTime() - _createdAt) - try { runnable.run() } finally { _completedTasksCounter.increment() } + try { runnable.run() } + finally { _completedTasksCounter.increment() } } } @@ -707,7 +810,8 @@ object ExecutorInstrumentation { _timeInQueueTimer.record(System.nanoTime() - _createdAt) val scope = Kamon.storeContext(_context) - try { runnable.run() } finally { + try { runnable.run() } + finally { _completedTasksCounter.increment() scope.close() } @@ -720,7 +824,8 @@ object ExecutorInstrumentation { override def call(): T = { _timeInQueueTimer.record(System.nanoTime() - _createdAt) - try { callable.call() } finally { _completedTasksCounter.increment() } + try { callable.call() } + finally { _completedTasksCounter.increment() } } } } @@ -734,7 +839,8 @@ object ExecutorInstrumentation { _timeInQueueTimer.record(System.nanoTime() - _createdAt) val scope = Kamon.storeContext(_context) - try { callable.call() } finally { + try { callable.call() } + finally { _completedTasksCounter.increment() scope.close() } @@ -747,7 +853,8 @@ object ExecutorInstrumentation { override def run(): Unit = { val scope = Kamon.storeContext(_context) - try { runnable.run() } finally { + try { runnable.run() } + finally { _completedTasksCounter.increment() scope.close() } @@ -760,7 +867,8 @@ object ExecutorInstrumentation { override def call(): T = { val scope = Kamon.storeContext(_context) - try { callable.call() } finally { + try { callable.call() } + finally { _completedTasksCounter.increment() scope.close() } @@ -774,7 +882,8 @@ object ExecutorInstrumentation { * to provide a shutdown method that can be used to clear shutdown the underlying ExecutorService and remove all the * metrics related to it. */ - class InstrumentedExecutionContext(ec: ExecutionContext, val underlyingExecutor: Option[ExecutorService]) extends ExecutionContext { + class InstrumentedExecutionContext(ec: ExecutionContext, val underlyingExecutor: Option[ExecutorService]) + extends ExecutionContext { override def execute(runnable: Runnable): Unit = ec.execute(runnable) diff --git a/instrumentation/kamon-executors/src/main/scala/kamon/instrumentation/executor/ExecutorMetrics.scala b/instrumentation/kamon-executors/src/main/scala/kamon/instrumentation/executor/ExecutorMetrics.scala index a2b997b2e..2ad952d1c 100644 --- a/instrumentation/kamon-executors/src/main/scala/kamon/instrumentation/executor/ExecutorMetrics.scala +++ b/instrumentation/kamon-executors/src/main/scala/kamon/instrumentation/executor/ExecutorMetrics.scala @@ -22,47 +22,47 @@ import kamon.tag.TagSet object ExecutorMetrics { - val MinThreads = Kamon.gauge ( + val MinThreads = Kamon.gauge( name = "executor.threads.min", description = "Tracks executor minimum number of Threads" ) - val MaxThreads = Kamon.gauge ( + val MaxThreads = Kamon.gauge( name = "executor.threads.max", description = "Tracks executor maximum number of Threads" ) - val Parallelism = Kamon.gauge ( + val Parallelism = Kamon.gauge( name = "executor.parallelism", description = "Tracks executor parallelism" ) - val ThreadsActive = Kamon.histogram ( + val ThreadsActive = Kamon.histogram( name = "executor.threads.active", description = "Samples the number of active threads on the executor service" ) - val ThreadsTotal = Kamon.histogram ( + val ThreadsTotal = Kamon.histogram( name = "executor.threads.total", description = "Samples the total number of threads on the executor service" ) - val TasksCompleted = Kamon.counter ( + val TasksCompleted = Kamon.counter( name = "executor.tasks.completed", description = "Tracks the number of tasks that completed execution on the executor service" ) - val TasksSubmitted = Kamon.counter ( + val TasksSubmitted = Kamon.counter( name = "executor.tasks.submitted", description = "Tracks the number of tasks submitted to the executor service" ) - val TimeInQueue = Kamon.timer ( + val TimeInQueue = Kamon.timer( name = "executor.time-in-queue", description = "Tracks the time that tasks spend on the executor service's queue" ) - val QueueSize = Kamon.histogram ( + val QueueSize = Kamon.histogram( name = "executor.queue-size", description = "Samples the number of tasks queued for execution on the executor service" ) diff --git a/instrumentation/kamon-executors/src/test/scala/kamon/instrumentation/executor/CaptureContextOnSubmitInstrumentationSpec.scala b/instrumentation/kamon-executors/src/test/scala/kamon/instrumentation/executor/CaptureContextOnSubmitInstrumentationSpec.scala index 4c37b10be..ecd64bd0e 100644 --- a/instrumentation/kamon-executors/src/test/scala/kamon/instrumentation/executor/CaptureContextOnSubmitInstrumentationSpec.scala +++ b/instrumentation/kamon-executors/src/test/scala/kamon/instrumentation/executor/CaptureContextOnSubmitInstrumentationSpec.scala @@ -13,7 +13,6 @@ * ========================================================================================= */ - package kamon.instrumentation.executor import com.google.common.util.concurrent.MoreExecutors @@ -27,7 +26,8 @@ import org.scalatest.wordspec.AnyWordSpec import java.util.concurrent.{Callable, CountDownLatch, TimeUnit, Executors => JavaExecutors} import scala.collection.mutable.ListBuffer -class CaptureContextOnSubmitInstrumentationSpec extends AnyWordSpec with Matchers with ContextTesting with Eventually with OptionValues { +class CaptureContextOnSubmitInstrumentationSpec extends AnyWordSpec with Matchers with ContextTesting with Eventually + with OptionValues { "the CaptureContextOnSubmitInstrumentation" should { "capture the context when call execute(Runnable) in DirectExecutor" in { @@ -38,7 +38,7 @@ class CaptureContextOnSubmitInstrumentationSpec extends AnyWordSpec with Matcher runnable.ctx } - ctx.value should be ("in-runnable-body") + ctx.value should be("in-runnable-body") } "capture the context when call execute(Runnable) in ThreadPool" in { @@ -50,7 +50,7 @@ class CaptureContextOnSubmitInstrumentationSpec extends AnyWordSpec with Matcher runnable.ctx } - ctx.value should be ("in-runnable-body") + ctx.value should be("in-runnable-body") } "capture the context when call submit(Runnable) in ThreadPool" in { @@ -62,7 +62,7 @@ class CaptureContextOnSubmitInstrumentationSpec extends AnyWordSpec with Matcher runnable.ctx } - ctx.value should be ("in-runnable-body") + ctx.value should be("in-runnable-body") } "capture the context when call execute(Runnable) in ForkJoinPool" in { @@ -75,7 +75,7 @@ class CaptureContextOnSubmitInstrumentationSpec extends AnyWordSpec with Matcher runnable.ctx } - ctx.value should be ("in-runnable-body") + ctx.value should be("in-runnable-body") } "capture the context when call submit(Runnable) in ForkJoinPool" in { @@ -88,7 +88,7 @@ class CaptureContextOnSubmitInstrumentationSpec extends AnyWordSpec with Matcher runnable.ctx } - ctx.value should be ("in-runnable-body") + ctx.value should be("in-runnable-body") } "capture the context when call execute(Runnable) in ScheduledThreadPool" in { @@ -101,7 +101,7 @@ class CaptureContextOnSubmitInstrumentationSpec extends AnyWordSpec with Matcher runnable.ctx } - ctx.value should be ("in-runnable-body") + ctx.value should be("in-runnable-body") } "capture the context when call submit(Runnable) in ScheduledThreadPool" in { @@ -114,7 +114,7 @@ class CaptureContextOnSubmitInstrumentationSpec extends AnyWordSpec with Matcher runnable.ctx } - ctx.value should be ("in-runnable-body") + ctx.value should be("in-runnable-body") } "capture the context when call schedule(Runnable,long,TimeUnit) in ScheduledThreadPool" in { @@ -127,7 +127,7 @@ class CaptureContextOnSubmitInstrumentationSpec extends AnyWordSpec with Matcher runnable.ctx } - ctx.value should be ("in-runnable-body") + ctx.value should be("in-runnable-body") } "capture the context when call submit(Callable) in ThreadPool" in { @@ -139,7 +139,7 @@ class CaptureContextOnSubmitInstrumentationSpec extends AnyWordSpec with Matcher callable.ctx } - ctx.value should be ("in-callable-body") + ctx.value should be("in-callable-body") } "capture the context when call submit(Callable) in ScheduledThreadPool" in { @@ -151,7 +151,7 @@ class CaptureContextOnSubmitInstrumentationSpec extends AnyWordSpec with Matcher callable.ctx } - ctx.value should be ("in-callable-body") + ctx.value should be("in-callable-body") } "capture the context when call schedule(Callable,long,TimeUnit) in ScheduledThreadPool" in { @@ -164,7 +164,7 @@ class CaptureContextOnSubmitInstrumentationSpec extends AnyWordSpec with Matcher callable.ctx } - ctx.value should be ("in-callable-body") + ctx.value should be("in-callable-body") } "capture the context when call submit(Callable) in ForkJoinPool" in { @@ -177,17 +177,20 @@ class CaptureContextOnSubmitInstrumentationSpec extends AnyWordSpec with Matcher callable.ctx } - ctx.value should be ("in-callable-body") + ctx.value should be("in-callable-body") } "capture the context when call invokeAll(Colection) in ExecutorService" in { import scala.collection.JavaConverters._ val values = Kamon.runWithContext(testContext("all-callables-should-see-this-key")) { - val callables = new CallableWithContext("A") :: new CallableWithContext( "B") :: new CallableWithContext("C") :: Nil - JavaExecutors.newCachedThreadPool().invokeAll(callables.asJava).asScala.foldLeft(ListBuffer.empty[String]) { (acc, f) => acc += f.get() } + val callables = + new CallableWithContext("A") :: new CallableWithContext("B") :: new CallableWithContext("C") :: Nil + JavaExecutors.newCachedThreadPool().invokeAll(callables.asJava).asScala.foldLeft(ListBuffer.empty[String]) { + (acc, f) => acc += f.get() + } } - values should contain allOf("all-callables-should-see-this-key-A", "all-callables-should-see-this-key-B", "all-callables-should-see-this-key-C") + values should contain allOf ("all-callables-should-see-this-key-A", "all-callables-should-see-this-key-B", "all-callables-should-see-this-key-C") } } } @@ -213,7 +216,7 @@ class SimpleCallable extends Callable[Option[String]] with ContextTesting { } } -class CallableWithContext[A](value:String) extends Callable[String] with ContextTesting { +class CallableWithContext[A](value: String) extends Callable[String] with ContextTesting { override def call(): String = Kamon.currentContext().getTag(Lookups.option(TestKey)).map(_ + s"-$value").getOrElse("undefined") -} \ No newline at end of file +} diff --git a/instrumentation/kamon-executors/src/test/scala/kamon/instrumentation/executor/ExecutorMetricsSpec.scala b/instrumentation/kamon-executors/src/test/scala/kamon/instrumentation/executor/ExecutorMetricsSpec.scala index b82d6a6b0..77c84570a 100644 --- a/instrumentation/kamon-executors/src/test/scala/kamon/instrumentation/executor/ExecutorMetricsSpec.scala +++ b/instrumentation/kamon-executors/src/test/scala/kamon/instrumentation/executor/ExecutorMetricsSpec.scala @@ -1,4 +1,3 @@ - /* * ========================================================================================= * Copyright © 2013-2017 the kamon project @@ -29,31 +28,31 @@ import org.scalatest.wordspec.AnyWordSpec import scala.concurrent.duration.Duration import scala.concurrent.{Await, Future, Promise} - -class ExecutorMetricsSpec extends AnyWordSpec with Matchers with InstrumentInspection.Syntax with MetricInspection.Syntax with Eventually - with InitAndStopKamonAfterAll { +class ExecutorMetricsSpec extends AnyWordSpec with Matchers with InstrumentInspection.Syntax + with MetricInspection.Syntax with Eventually + with InitAndStopKamonAfterAll { implicit override val patienceConfig = PatienceConfig(timeout = scaled(Span(2000, Millis)), interval = scaled(Span(20, Millis))) - "the ExecutorServiceMetrics" should { "register a ThreadPoolExecutor, collect their metrics and remove it" in { val threadPoolExecutor = JavaExecutors.newCachedThreadPool() val registeredPool = ExecutorInstrumentation.instrument(threadPoolExecutor, "thread-pool-executor-metrics") - ExecutorMetrics.ThreadsActive.tagValues("name") should contain ("thread-pool-executor-metrics") - ExecutorMetrics.ThreadsActive.tagValues("type") should contain ("ThreadPoolExecutor") + ExecutorMetrics.ThreadsActive.tagValues("name") should contain("thread-pool-executor-metrics") + ExecutorMetrics.ThreadsActive.tagValues("type") should contain("ThreadPoolExecutor") registeredPool.shutdown() } "register a ScheduledThreadPoolExecutor, collect their metrics and remove it" in { val scheduledThreadPoolExecutor = JavaExecutors.newScheduledThreadPool(1) - val registeredPool = ExecutorInstrumentation.instrument(scheduledThreadPoolExecutor, "scheduled-thread-pool-executor-metrics") + val registeredPool = + ExecutorInstrumentation.instrument(scheduledThreadPoolExecutor, "scheduled-thread-pool-executor-metrics") - ExecutorMetrics.ThreadsActive.tagValues("name") should contain ("scheduled-thread-pool-executor-metrics") - ExecutorMetrics.ThreadsActive.tagValues("type") should contain ("ThreadPoolExecutor") + ExecutorMetrics.ThreadsActive.tagValues("name") should contain("scheduled-thread-pool-executor-metrics") + ExecutorMetrics.ThreadsActive.tagValues("type") should contain("ThreadPoolExecutor") registeredPool.shutdown() } @@ -62,8 +61,8 @@ class ExecutorMetricsSpec extends AnyWordSpec with Matchers with InstrumentInspe val javaForkJoinPool = JavaExecutors.newWorkStealingPool() val registeredForkJoin = ExecutorInstrumentation.instrument(javaForkJoinPool, "java-fork-join-pool-metrics") - ExecutorMetrics.ThreadsActive.tagValues("name") should contain ("java-fork-join-pool-metrics") - ExecutorMetrics.ThreadsActive.tagValues("type") should contain ("ForkJoinPool") + ExecutorMetrics.ThreadsActive.tagValues("name") should contain("java-fork-join-pool-metrics") + ExecutorMetrics.ThreadsActive.tagValues("type") should contain("ForkJoinPool") registeredForkJoin.shutdown() } @@ -72,8 +71,8 @@ class ExecutorMetricsSpec extends AnyWordSpec with Matchers with InstrumentInspe val scalaForkJoinPool = new ScalaForkJoinPool(10) val registeredForkJoin = ExecutorInstrumentation.instrument(scalaForkJoinPool, "scala-fork-join-pool-metrics") - ExecutorMetrics.ThreadsActive.tagValues("name") should contain ("scala-fork-join-pool-metrics") - ExecutorMetrics.ThreadsActive.tagValues("type") should contain ("ForkJoinPool") + ExecutorMetrics.ThreadsActive.tagValues("name") should contain("scala-fork-join-pool-metrics") + ExecutorMetrics.ThreadsActive.tagValues("type") should contain("ForkJoinPool") registeredForkJoin.shutdown() } @@ -92,7 +91,7 @@ class ExecutorMetricsSpec extends AnyWordSpec with Matchers with InstrumentInspe new TestPool(executor) def poolInstruments(testPool: TestPool): ExecutorMetrics.ThreadPoolInstruments = testPool.executor match { - case tpe:ThreadPoolExecutor => new ExecutorMetrics.ThreadPoolInstruments(testPool.name, TagSet.Empty) + case tpe: ThreadPoolExecutor => new ExecutorMetrics.ThreadPoolInstruments(testPool.name, TagSet.Empty) case javaFjp: ForkJoinPool => new ExecutorMetrics.ForkJoinPoolInstruments(testPool.name, TagSet.Empty) case scalaFjp: ScalaForkJoinPool => new ExecutorMetrics.ForkJoinPoolInstruments(testPool.name, TagSet.Empty) } @@ -100,13 +99,12 @@ class ExecutorMetricsSpec extends AnyWordSpec with Matchers with InstrumentInspe def fjpInstruments(testPool: TestPool): ExecutorMetrics.ForkJoinPoolInstruments = new ExecutorMetrics.ForkJoinPoolInstruments(testPool.name, TagSet.Empty) - def commonExecutorBehaviour(executor: Int => ExecutorService, size: Int) = { "track settings" in { val pool = setupTestPool(executor(size)) val metrics = poolInstruments(pool) - eventually(metrics.poolMax.value should be (size)) + eventually(metrics.poolMax.value should be(size)) pool.close() } @@ -116,29 +114,30 @@ class ExecutorMetricsSpec extends AnyWordSpec with Matchers with InstrumentInspe val semaphore = Promise[String]() eventually { - metrics.submittedTasks.value(false) should be (0) - metrics.completedTasks.value(false) should be (0) + metrics.submittedTasks.value(false) should be(0) + metrics.completedTasks.value(false) should be(0) } val blockedTask = new Runnable { override def run(): Unit = { Await.result(semaphore.future, Duration.Inf) () - }} + } + } pool.submit(blockedTask) eventually { - (metrics.submittedTasks.value(false), metrics.completedTasks.value(false)) should be (1, 0) + (metrics.submittedTasks.value(false), metrics.completedTasks.value(false)) should be(1, 0) } semaphore.success("done") eventually { - (metrics.submittedTasks.value(false), metrics.submittedTasks.value(false)) should be (1, 1) + (metrics.submittedTasks.value(false), metrics.submittedTasks.value(false)) should be(1, 1) } (1 to 10).foreach(_ => pool.submit(blockedTask)) eventually { - (metrics.submittedTasks.value(false), metrics.submittedTasks.value(false)) should be (11, 11) + (metrics.submittedTasks.value(false), metrics.submittedTasks.value(false)) should be(11, 11) } pool.close() } @@ -148,19 +147,21 @@ class ExecutorMetricsSpec extends AnyWordSpec with Matchers with InstrumentInspe val metrics = poolInstruments(pool) eventually { - metrics.totalThreads.distribution(false).max should be (0) - metrics.activeThreads.distribution(false).max should be (0) + metrics.totalThreads.distribution(false).max should be(0) + metrics.activeThreads.distribution(false).max should be(0) } Future( - (1 to 10000).foreach(_ => pool.submit(new Runnable { - override def run(): Unit = Thread.sleep(1) - })) + (1 to 10000).foreach(_ => + pool.submit(new Runnable { + override def run(): Unit = Thread.sleep(1) + }) + ) )(scala.concurrent.ExecutionContext.global) eventually { - metrics.activeThreads.distribution(false).max should be (2) - metrics.totalThreads.distribution(false).max should be (2) + metrics.activeThreads.distribution(false).max should be(2) + metrics.totalThreads.distribution(false).max should be(2) } pool.close() } @@ -174,9 +175,10 @@ class ExecutorMetricsSpec extends AnyWordSpec with Matchers with InstrumentInspe override def run(): Unit = { Await.result(semaphore.future, Duration.Inf) () - }} + } + } - eventually(metrics.queuedTasks.distribution(false).max should be (0)) + eventually(metrics.queuedTasks.distribution(false).max should be(0)) (1 to 100).foreach(_ => pool.submit(blockedTask)) @@ -197,8 +199,8 @@ class ExecutorMetricsSpec extends AnyWordSpec with Matchers with InstrumentInspe "track FJP specific metrics" in { eventually { - metrics.parallelism.value should be (size) - metrics.poolMin.value should be (0) + metrics.parallelism.value should be(size) + metrics.poolMin.value should be(0) } pool.close() } @@ -210,7 +212,7 @@ class ExecutorMetricsSpec extends AnyWordSpec with Matchers with InstrumentInspe "track TPE specific metrics" in { eventually { - metrics.poolMin.value should be (size) + metrics.poolMin.value should be(size) pool.close() } @@ -234,4 +236,3 @@ class ExecutorMetricsSpec extends AnyWordSpec with Matchers with InstrumentInspe } } } - diff --git a/instrumentation/kamon-executors/src/test/scala/kamon/instrumentation/executor/ExecutorsRegistrationSpec.scala b/instrumentation/kamon-executors/src/test/scala/kamon/instrumentation/executor/ExecutorsRegistrationSpec.scala index c34a032b0..342690a68 100644 --- a/instrumentation/kamon-executors/src/test/scala/kamon/instrumentation/executor/ExecutorsRegistrationSpec.scala +++ b/instrumentation/kamon-executors/src/test/scala/kamon/instrumentation/executor/ExecutorsRegistrationSpec.scala @@ -27,14 +27,19 @@ import org.scalatest.wordspec.AnyWordSpec import scala.concurrent.ExecutionContext -class ExecutorsRegistrationSpec extends AnyWordSpec with Matchers with MetricInspection.Syntax with InitAndStopKamonAfterAll { +class ExecutorsRegistrationSpec extends AnyWordSpec with Matchers with MetricInspection.Syntax + with InitAndStopKamonAfterAll { "the Executors registration function" should { "accept all types of known executors" in { - val registeredForkJoin = ExecutorInstrumentation.instrument(new JavaForkJoinPool(1), "fjp") + val registeredForkJoin = ExecutorInstrumentation.instrument(new JavaForkJoinPool(1), "fjp") val registeredThreadPool = ExecutorInstrumentation.instrument(JavaExecutors.newFixedThreadPool(1), "thread-pool") - val registeredScheduled = ExecutorInstrumentation.instrument(JavaExecutors.newScheduledThreadPool(1), "scheduled-thread-pool") - val registeredExecContext = ExecutorInstrumentation.instrumentExecutionContext(ExecutionContext.fromExecutorService(JavaExecutors.newFixedThreadPool(1)), "execution-context") + val registeredScheduled = + ExecutorInstrumentation.instrument(JavaExecutors.newScheduledThreadPool(1), "scheduled-thread-pool") + val registeredExecContext = ExecutorInstrumentation.instrumentExecutionContext( + ExecutionContext.fromExecutorService(JavaExecutors.newFixedThreadPool(1)), + "execution-context" + ) assertContainsAllExecutorNames(ThreadsActive.tagValues("name")) assertContainsAllExecutorNames(TasksSubmitted.tagValues("name")) diff --git a/instrumentation/kamon-executors/src/test/scala/kamon/instrumentation/executor/OnSubmitContextPropagationSpec.scala b/instrumentation/kamon-executors/src/test/scala/kamon/instrumentation/executor/OnSubmitContextPropagationSpec.scala index bf3bcb454..5927cdf24 100644 --- a/instrumentation/kamon-executors/src/test/scala/kamon/instrumentation/executor/OnSubmitContextPropagationSpec.scala +++ b/instrumentation/kamon-executors/src/test/scala/kamon/instrumentation/executor/OnSubmitContextPropagationSpec.scala @@ -13,7 +13,6 @@ * ========================================================================================= */ - package kamon.instrumentation.executor import java.util.concurrent.{ExecutorService, Executors => JavaExecutors} @@ -29,7 +28,8 @@ import org.scalatest.wordspec.AnyWordSpec import scala.collection.mutable.ListBuffer import scala.util.Random -class OnSubmitContextPropagationSpec extends AnyWordSpec with Matchers with ContextTesting with Eventually with OptionValues +class OnSubmitContextPropagationSpec extends AnyWordSpec with Matchers with ContextTesting with Eventually + with OptionValues with InitAndStopKamonAfterAll { "an instrumented executor with context propagation on submit enabled" should { @@ -41,7 +41,7 @@ class OnSubmitContextPropagationSpec extends AnyWordSpec with Matchers with Cont runnable.ctx } - ctx.value should be ("in-runnable-body") + ctx.value should be("in-runnable-body") } "capture the context when call execute(Runnable) in ThreadPool" in { @@ -53,7 +53,7 @@ class OnSubmitContextPropagationSpec extends AnyWordSpec with Matchers with Cont runnable.ctx } - ctx.value should be ("in-runnable-body") + ctx.value should be("in-runnable-body") } "capture the context when call submit(Runnable) in ThreadPool" in { @@ -65,7 +65,7 @@ class OnSubmitContextPropagationSpec extends AnyWordSpec with Matchers with Cont runnable.ctx } - ctx.value should be ("in-runnable-body") + ctx.value should be("in-runnable-body") } "capture the context when call execute(Runnable) in ForkJoinPool" in { @@ -78,7 +78,7 @@ class OnSubmitContextPropagationSpec extends AnyWordSpec with Matchers with Cont runnable.ctx } - ctx.value should be ("in-runnable-body") + ctx.value should be("in-runnable-body") } "capture the context when call submit(Runnable) in ForkJoinPool" in { @@ -91,7 +91,7 @@ class OnSubmitContextPropagationSpec extends AnyWordSpec with Matchers with Cont runnable.ctx } - ctx.value should be ("in-runnable-body") + ctx.value should be("in-runnable-body") } "capture the context when call execute(Runnable) in ScheduledThreadPool" in { @@ -104,7 +104,7 @@ class OnSubmitContextPropagationSpec extends AnyWordSpec with Matchers with Cont runnable.ctx } - ctx.value should be ("in-runnable-body") + ctx.value should be("in-runnable-body") } "capture the context when call submit(Runnable) in ScheduledThreadPool" in { @@ -117,7 +117,7 @@ class OnSubmitContextPropagationSpec extends AnyWordSpec with Matchers with Cont runnable.ctx } - ctx.value should be ("in-runnable-body") + ctx.value should be("in-runnable-body") } "capture the context when call submit(Callable) in ThreadPool" in { @@ -129,7 +129,7 @@ class OnSubmitContextPropagationSpec extends AnyWordSpec with Matchers with Cont callable.ctx } - ctx.value should be ("in-callable-body") + ctx.value should be("in-callable-body") } "capture the context when call submit(Callable) in ScheduledThreadPool" in { @@ -141,7 +141,7 @@ class OnSubmitContextPropagationSpec extends AnyWordSpec with Matchers with Cont callable.ctx } - ctx.value should be ("in-callable-body") + ctx.value should be("in-callable-body") } "capture the context when call submit(Callable) in ForkJoinPool" in { @@ -154,21 +154,28 @@ class OnSubmitContextPropagationSpec extends AnyWordSpec with Matchers with Cont callable.ctx } - ctx.value should be ("in-callable-body") + ctx.value should be("in-callable-body") } "capture the context when call invokeAll(Collection) in ExecutorService" in { import scala.collection.JavaConverters._ val values = Kamon.runWithContext(testContext("all-callables-should-see-this-key")) { - val callables = new CallableWithContext("A") :: new CallableWithContext( "B") :: new CallableWithContext("C") :: Nil - instrument(JavaExecutors.newCachedThreadPool()).invokeAll(callables.asJava).asScala.foldLeft(ListBuffer.empty[String]) { (acc, f) => acc += f.get() } + val callables = + new CallableWithContext("A") :: new CallableWithContext("B") :: new CallableWithContext("C") :: Nil + instrument(JavaExecutors.newCachedThreadPool()).invokeAll(callables.asJava).asScala.foldLeft( + ListBuffer.empty[String] + ) { (acc, f) => acc += f.get() } } - values should contain allOf("all-callables-should-see-this-key-A", "all-callables-should-see-this-key-B", "all-callables-should-see-this-key-C") + values should contain allOf ("all-callables-should-see-this-key-A", "all-callables-should-see-this-key-B", "all-callables-should-see-this-key-C") } } def instrument(executor: ExecutorService): ExecutorService = { - ExecutorInstrumentation.instrument(executor, Random.nextString(10), ExecutorInstrumentation.DefaultSettings.propagateContextOnSubmit()) + ExecutorInstrumentation.instrument( + executor, + Random.nextString(10), + ExecutorInstrumentation.DefaultSettings.propagateContextOnSubmit() + ) } -} \ No newline at end of file +} diff --git a/instrumentation/kamon-finagle/src/main/scala/kamon/instrumentation/finagle/client/IdConversionOps.scala b/instrumentation/kamon-finagle/src/main/scala/kamon/instrumentation/finagle/client/IdConversionOps.scala index 7593906f4..95cb68ac2 100644 --- a/instrumentation/kamon-finagle/src/main/scala/kamon/instrumentation/finagle/client/IdConversionOps.scala +++ b/instrumentation/kamon-finagle/src/main/scala/kamon/instrumentation/finagle/client/IdConversionOps.scala @@ -32,7 +32,7 @@ private[finagle] object IdConversionOps { def toTraceId: TraceId = toTraceId(None) def toTraceId(parent: Span): TraceId = parent match { case Span.Empty => toTraceId - case _ => toTraceId(Some(parent)) + case _ => toTraceId(Some(parent)) } private def toTraceId(parent: Option[Span]): TraceId = { if (span.id.isEmpty || span.trace.id.isEmpty) Trace.nextId @@ -42,9 +42,9 @@ private[finagle] object IdConversionOps { parentId = parent.map(p => SpanId(p.id.toLongId)), spanId = SpanId(span.id.toLongId), sampled = span.trace.samplingDecision match { - case SamplingDecision.Sample => Some(true) + case SamplingDecision.Sample => Some(true) case SamplingDecision.DoNotSample => Some(false) - case _ => None + case _ => None } ) } diff --git a/instrumentation/kamon-finagle/src/main/scala/kamon/instrumentation/finagle/client/KamonFinagleTracer.scala b/instrumentation/kamon-finagle/src/main/scala/kamon/instrumentation/finagle/client/KamonFinagleTracer.scala index 72aebee95..4ff5a8e2b 100644 --- a/instrumentation/kamon-finagle/src/main/scala/kamon/instrumentation/finagle/client/KamonFinagleTracer.scala +++ b/instrumentation/kamon-finagle/src/main/scala/kamon/instrumentation/finagle/client/KamonFinagleTracer.scala @@ -34,31 +34,31 @@ final class KamonFinagleTracer extends Tracer { private def recordToSpan(record: Record, span: Span): Unit = { record.annotation match { - case Annotation.Rpc(name) => span.tag(Tags.Keys.ResourceName, name) - case Annotation.Message(msg) => span.tag("message", msg) - case Annotation.BinaryAnnotation(name, s: String) => span.tag(name, s) - case Annotation.BinaryAnnotation(name, i: Int) => span.tag(name, i) - case Annotation.BinaryAnnotation(name, i: Long) => span.tag(name, i) - case Annotation.BinaryAnnotation(name, b: Boolean) => span.tag(name, b) + case Annotation.Rpc(name) => span.tag(Tags.Keys.ResourceName, name) + case Annotation.Message(msg) => span.tag("message", msg) + case Annotation.BinaryAnnotation(name, s: String) => span.tag(name, s) + case Annotation.BinaryAnnotation(name, i: Int) => span.tag(name, i) + case Annotation.BinaryAnnotation(name, i: Long) => span.tag(name, i) + case Annotation.BinaryAnnotation(name, b: Boolean) => span.tag(name, b) case Annotation.BinaryAnnotation(name, t: Throwable) => span.fail(name, t) - case Annotation.BinaryAnnotation(name, other) => span.tag(name, other.toString) - case Annotation.WireSend => Tags.mark(span, "wire/send", record.timestamp) - case Annotation.WireRecv => Tags.mark(span, "wire/recv", record.timestamp) - case Annotation.WireRecvError(msg) => Tags.fail(span, "wire/recv_error", msg, record.timestamp) - case Annotation.ClientAddr(addr) => Tags.setPeer(span, addr) - case Annotation.ClientSend => Tags.mark(span, "client/send", record.timestamp) - case Annotation.ClientRecv => Tags.mark(span, "client/recv", record.timestamp) + case Annotation.BinaryAnnotation(name, other) => span.tag(name, other.toString) + case Annotation.WireSend => Tags.mark(span, "wire/send", record.timestamp) + case Annotation.WireRecv => Tags.mark(span, "wire/recv", record.timestamp) + case Annotation.WireRecvError(msg) => Tags.fail(span, "wire/recv_error", msg, record.timestamp) + case Annotation.ClientAddr(addr) => Tags.setPeer(span, addr) + case Annotation.ClientSend => Tags.mark(span, "client/send", record.timestamp) + case Annotation.ClientRecv => Tags.mark(span, "client/recv", record.timestamp) case Annotation.ClientRecvError(msg) => Tags.fail(span, s"client/recv_error", msg, record.timestamp) - case Annotation.ServerAddr(addr) => Tags.setPeer(span, addr) - case Annotation.ServerRecv => Tags.mark(span, "server/recv", record.timestamp) - case Annotation.ServerSend => Tags.mark(span, "server/send", record.timestamp) + case Annotation.ServerAddr(addr) => Tags.setPeer(span, addr) + case Annotation.ServerRecv => Tags.mark(span, "server/recv", record.timestamp) + case Annotation.ServerSend => Tags.mark(span, "server/send", record.timestamp) case Annotation.ServerSendError(msg) => Tags.fail(span, "server/send_error", msg, record.timestamp) case Annotation.LocalAddr(addr) => span .tag("local.hostname", addr.getHostString) .tag("local.port", addr.getPort) case Annotation.ServiceName(name) => span.tag("finagle.service_name", name) - case annotation => log.debug(s"dropping unhandled annotation $annotation") + case annotation => log.debug(s"dropping unhandled annotation $annotation") } } diff --git a/instrumentation/kamon-finagle/src/main/scala/kamon/instrumentation/finagle/client/SpanInitializer.scala b/instrumentation/kamon-finagle/src/main/scala/kamon/instrumentation/finagle/client/SpanInitializer.scala index d420911bc..ebf786a9d 100644 --- a/instrumentation/kamon-finagle/src/main/scala/kamon/instrumentation/finagle/client/SpanInitializer.scala +++ b/instrumentation/kamon-finagle/src/main/scala/kamon/instrumentation/finagle/client/SpanInitializer.scala @@ -30,6 +30,7 @@ import kamon.trace.Span */ object SpanInitializer { private[kamon] val role = Stack.Role("SpanInitializer") + /** * Set a Finagle trace for the duration of the call to `f`. * diff --git a/instrumentation/kamon-finagle/src/test/scala/kamon/instrumentation/finagle/client/HttpClientOpsSpec.scala b/instrumentation/kamon-finagle/src/test/scala/kamon/instrumentation/finagle/client/HttpClientOpsSpec.scala index 0eea2aa25..b08d0a9c7 100644 --- a/instrumentation/kamon-finagle/src/test/scala/kamon/instrumentation/finagle/client/HttpClientOpsSpec.scala +++ b/instrumentation/kamon-finagle/src/test/scala/kamon/instrumentation/finagle/client/HttpClientOpsSpec.scala @@ -21,7 +21,8 @@ import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.duration._ import scala.concurrent.{Await, Future, Promise} -class HttpClientOpsSpec extends AnyWordSpecLike with Matchers with Reconfigure with InitAndStopKamonAfterAll with BeforeAndAfterAll { +class HttpClientOpsSpec extends AnyWordSpecLike with Matchers with Reconfigure with InitAndStopKamonAfterAll + with BeforeAndAfterAll { override protected def beforeAll(): Unit = { super.beforeAll() applyConfig(HttpClientOpsSpec.Config) @@ -50,7 +51,7 @@ class HttpClientOpsSpec extends AnyWordSpecLike with Matchers with Reconfigure w } "set marks for standard finagle annotations" in { - span.marks.map(_.key) should contain allOf("wire/recv", "wire/send", "client/send") + span.marks.map(_.key) should contain allOf ("wire/recv", "wire/send", "client/send") } "add trace propagation headers to the request" in { @@ -112,17 +113,17 @@ object HttpClientOpsSpec { // TraceInitializerFilter will clear b3 headers before we can check them in the test. .withStack(_.remove(TraceInitializerFilter.role)) .serve( - ":*", - new Service[Request, Response] { - def apply(request: Request): twitterutil.Future[Response] = { - requestReceived.success(request) - request.path match { - case "/ok" => twitterutil.Future.value(Response()) - case "/oops" => twitterutil.Future.value(Response().statusCode(400)) + ":*", + new Service[Request, Response] { + def apply(request: Request): twitterutil.Future[Response] = { + requestReceived.success(request) + request.path match { + case "/ok" => twitterutil.Future.value(Response()) + case "/oops" => twitterutil.Future.value(Response().statusCode(400)) + } } } - } - ) + ) val port: Int = server.boundAddress.asInstanceOf[InetSocketAddress].getPort def close(): Future[Unit] = server.close().as[Future[Unit]] } @@ -167,5 +168,3 @@ object HttpClientOpsSpec { } } } - - diff --git a/instrumentation/kamon-http4s-0.23/src/main/scala/kamon/http4s/Http4s.scala b/instrumentation/kamon-http4s-0.23/src/main/scala/kamon/http4s/Http4s.scala index 271529191..9b20ef814 100644 --- a/instrumentation/kamon-http4s-0.23/src/main/scala/kamon/http4s/Http4s.scala +++ b/instrumentation/kamon-http4s-0.23/src/main/scala/kamon/http4s/Http4s.scala @@ -26,7 +26,7 @@ object Http4s { nameGeneratorFromConfig(Kamon.config()) private def nameGeneratorFromConfig( - config: Config + config: Config ): HttpOperationNameGenerator = { val dynamic = new DynamicAccess(getClass.getClassLoader) val nameGeneratorFQCN = config.getString( diff --git a/instrumentation/kamon-http4s-0.23/src/main/scala/kamon/http4s/middleware/client/KamonSupport.scala b/instrumentation/kamon-http4s-0.23/src/main/scala/kamon/http4s/middleware/client/KamonSupport.scala index 48c2fbe5b..96024783e 100644 --- a/instrumentation/kamon-http4s-0.23/src/main/scala/kamon/http4s/middleware/client/KamonSupport.scala +++ b/instrumentation/kamon-http4s-0.23/src/main/scala/kamon/http4s/middleware/client/KamonSupport.scala @@ -31,7 +31,7 @@ object KamonSupport { private var _instrumentation = instrumentation(Kamon.config()) private def instrumentation( - kamonConfig: Config + kamonConfig: Config ): HttpClientInstrumentation = { val httpClientConfig = kamonConfig.getConfig("kamon.instrumentation.http4s.client") @@ -50,9 +50,9 @@ object KamonSupport { } private def kamonClient[F[_]]( - underlying: Client[F] + underlying: Client[F] )(request: Request[F])(ctx: Context)( - instrumentation: HttpClientInstrumentation + instrumentation: HttpClientInstrumentation )(implicit F: Sync[F]): Resource[F, Response[F]] = for { requestHandler <- Resource.eval( @@ -63,8 +63,8 @@ object KamonSupport { } yield trackedResponse def handleResponse[F[_]]( - response: Either[Throwable, Response[F]], - requestHandler: HttpClientInstrumentation.RequestHandler[Request[F]] + response: Either[Throwable, Response[F]], + requestHandler: HttpClientInstrumentation.RequestHandler[Request[F]] )(implicit F: Sync[F]): F[Response[F]] = response match { case Right(res) => diff --git a/instrumentation/kamon-http4s-0.23/src/main/scala/kamon/http4s/middleware/server/KamonSupport.scala b/instrumentation/kamon-http4s-0.23/src/main/scala/kamon/http4s/middleware/server/KamonSupport.scala index 57c09800c..e11cf986e 100644 --- a/instrumentation/kamon-http4s-0.23/src/main/scala/kamon/http4s/middleware/server/KamonSupport.scala +++ b/instrumentation/kamon-http4s-0.23/src/main/scala/kamon/http4s/middleware/server/KamonSupport.scala @@ -29,9 +29,9 @@ import org.http4s.{HttpRoutes, Request, Response} object KamonSupport { def apply[F[_]: Sync]( - service: HttpRoutes[F], - interface: String, - port: Int + service: HttpRoutes[F], + interface: String, + port: Int ): HttpRoutes[F] = { val httpServerConfig = Kamon.config().getConfig("kamon.instrumentation.http4s.server") @@ -46,8 +46,8 @@ object KamonSupport { } private def kamonService[F[_]]( - service: HttpRoutes[F], - instrumentation: HttpServerInstrumentation + service: HttpRoutes[F], + instrumentation: HttpServerInstrumentation )(request: Request[F])(implicit F: Sync[F]): OptionT[F, Response[F]] = OptionT { getHandler(instrumentation)(request).use { handler => @@ -63,21 +63,21 @@ object KamonSupport { } private def processRequest[F[_]]( - requestHandler: RequestHandler + requestHandler: RequestHandler )(implicit F: Sync[F]): Resource[F, RequestHandler] = Resource.make(F.delay(requestHandler.requestReceived()))(h => F.delay(h.responseSent()) ) private def withContext[F[_]]( - requestHandler: RequestHandler + requestHandler: RequestHandler )(implicit F: Sync[F]): Resource[F, Storage.Scope] = Resource.make(F.delay(Kamon.storeContext(requestHandler.context)))(scope => F.delay(scope.close()) ) private def getHandler[F[_]]( - instrumentation: HttpServerInstrumentation + instrumentation: HttpServerInstrumentation )(request: Request[F])(implicit F: Sync[F]): Resource[F, RequestHandler] = for { handler <- Resource.eval( @@ -88,9 +88,9 @@ object KamonSupport { } yield handler private def kamonServiceHandler[F[_]]( - requestHandler: RequestHandler, - e: Either[Throwable, Option[Response[F]]], - settings: HttpServerInstrumentation.Settings + requestHandler: RequestHandler, + e: Either[Throwable, Option[Response[F]]], + settings: HttpServerInstrumentation.Settings )(implicit F: Sync[F]): F[Option[Response[F]]] = e match { case Left(e) => diff --git a/instrumentation/kamon-http4s-0.23/src/main/scala/kamon/http4s/package.scala b/instrumentation/kamon-http4s-0.23/src/main/scala/kamon/http4s/package.scala index a02b46e5c..8fc69f9a6 100644 --- a/instrumentation/kamon-http4s-0.23/src/main/scala/kamon/http4s/package.scala +++ b/instrumentation/kamon-http4s-0.23/src/main/scala/kamon/http4s/package.scala @@ -52,7 +52,7 @@ package object http4s { } def getResponseBuilder[F[_]]( - response: Response[F] + response: Response[F] ): ResponseBuilder[Response[F]] = new HttpMessage.ResponseBuilder[Response[F]] { private var _headers = response.headers @@ -66,7 +66,7 @@ package object http4s { } def getRequestBuilder[F[_]]( - request: Request[F] + request: Request[F] ): HttpMessage.RequestBuilder[Request[F]] = new HttpMessage.RequestBuilder[Request[F]] { private var _headers = request.headers diff --git a/instrumentation/kamon-http4s-0.23/src/test/scala/kamon/http4s/HttpMetricsSpec.scala b/instrumentation/kamon-http4s-0.23/src/test/scala/kamon/http4s/HttpMetricsSpec.scala index 6d3fc2a5a..649a18cb8 100644 --- a/instrumentation/kamon-http4s-0.23/src/test/scala/kamon/http4s/HttpMetricsSpec.scala +++ b/instrumentation/kamon-http4s-0.23/src/test/scala/kamon/http4s/HttpMetricsSpec.scala @@ -35,7 +35,6 @@ import org.scalatest.{OptionValues, time} import org.scalatest.wordspec.AnyWordSpec import org.scalatest.matchers.should.Matchers - class HttpMetricsSpec extends AnyWordSpec with Matchers @@ -70,7 +69,7 @@ class HttpMetricsSpec ) def withServerAndClient[A]( - f: (Server, Client[IO], HttpServerMetrics.HttpServerInstruments) => IO[A] + f: (Server, Client[IO], HttpServerMetrics.HttpServerInstruments) => IO[A] ): A = (srv, client, metrics).tupled.use(f.tupled).unsafeRunSync() @@ -84,7 +83,7 @@ class HttpMetricsSpec } private def get[F[_]: Concurrent]( - path: String + path: String )(server: Server, client: Client[F]): F[String] = { client.expect[String](s"http://127.0.0.1:${server.address.getPort}$path") } diff --git a/instrumentation/kamon-http4s-0.23/src/test/scala/kamon/http4s/ServerInstrumentationSpec.scala b/instrumentation/kamon-http4s-0.23/src/test/scala/kamon/http4s/ServerInstrumentationSpec.scala index 8cb381a1a..9037bd50f 100644 --- a/instrumentation/kamon-http4s-0.23/src/test/scala/kamon/http4s/ServerInstrumentationSpec.scala +++ b/instrumentation/kamon-http4s-0.23/src/test/scala/kamon/http4s/ServerInstrumentationSpec.scala @@ -71,7 +71,7 @@ class ServerInstrumentationSpec (srv, client).tupled.use(f.tupled).unsafeRunSync() private def getResponse[F[_]: Concurrent]( - path: String + path: String )(server: Server, client: Client[F]): F[(String, Headers)] = { client.get(s"http://127.0.0.1:${server.address.getPort}$path") { r => r.bodyText.compile.toList.map(_.mkString).map(_ -> r.headers) diff --git a/instrumentation/kamon-http4s-1.0/src/main/scala/kamon/http4s/Http4s.scala b/instrumentation/kamon-http4s-1.0/src/main/scala/kamon/http4s/Http4s.scala index 271529191..9b20ef814 100644 --- a/instrumentation/kamon-http4s-1.0/src/main/scala/kamon/http4s/Http4s.scala +++ b/instrumentation/kamon-http4s-1.0/src/main/scala/kamon/http4s/Http4s.scala @@ -26,7 +26,7 @@ object Http4s { nameGeneratorFromConfig(Kamon.config()) private def nameGeneratorFromConfig( - config: Config + config: Config ): HttpOperationNameGenerator = { val dynamic = new DynamicAccess(getClass.getClassLoader) val nameGeneratorFQCN = config.getString( diff --git a/instrumentation/kamon-http4s-1.0/src/main/scala/kamon/http4s/middleware/client/KamonSupport.scala b/instrumentation/kamon-http4s-1.0/src/main/scala/kamon/http4s/middleware/client/KamonSupport.scala index 48c2fbe5b..96024783e 100644 --- a/instrumentation/kamon-http4s-1.0/src/main/scala/kamon/http4s/middleware/client/KamonSupport.scala +++ b/instrumentation/kamon-http4s-1.0/src/main/scala/kamon/http4s/middleware/client/KamonSupport.scala @@ -31,7 +31,7 @@ object KamonSupport { private var _instrumentation = instrumentation(Kamon.config()) private def instrumentation( - kamonConfig: Config + kamonConfig: Config ): HttpClientInstrumentation = { val httpClientConfig = kamonConfig.getConfig("kamon.instrumentation.http4s.client") @@ -50,9 +50,9 @@ object KamonSupport { } private def kamonClient[F[_]]( - underlying: Client[F] + underlying: Client[F] )(request: Request[F])(ctx: Context)( - instrumentation: HttpClientInstrumentation + instrumentation: HttpClientInstrumentation )(implicit F: Sync[F]): Resource[F, Response[F]] = for { requestHandler <- Resource.eval( @@ -63,8 +63,8 @@ object KamonSupport { } yield trackedResponse def handleResponse[F[_]]( - response: Either[Throwable, Response[F]], - requestHandler: HttpClientInstrumentation.RequestHandler[Request[F]] + response: Either[Throwable, Response[F]], + requestHandler: HttpClientInstrumentation.RequestHandler[Request[F]] )(implicit F: Sync[F]): F[Response[F]] = response match { case Right(res) => diff --git a/instrumentation/kamon-http4s-1.0/src/main/scala/kamon/http4s/middleware/server/KamonSupport.scala b/instrumentation/kamon-http4s-1.0/src/main/scala/kamon/http4s/middleware/server/KamonSupport.scala index 57c09800c..e11cf986e 100644 --- a/instrumentation/kamon-http4s-1.0/src/main/scala/kamon/http4s/middleware/server/KamonSupport.scala +++ b/instrumentation/kamon-http4s-1.0/src/main/scala/kamon/http4s/middleware/server/KamonSupport.scala @@ -29,9 +29,9 @@ import org.http4s.{HttpRoutes, Request, Response} object KamonSupport { def apply[F[_]: Sync]( - service: HttpRoutes[F], - interface: String, - port: Int + service: HttpRoutes[F], + interface: String, + port: Int ): HttpRoutes[F] = { val httpServerConfig = Kamon.config().getConfig("kamon.instrumentation.http4s.server") @@ -46,8 +46,8 @@ object KamonSupport { } private def kamonService[F[_]]( - service: HttpRoutes[F], - instrumentation: HttpServerInstrumentation + service: HttpRoutes[F], + instrumentation: HttpServerInstrumentation )(request: Request[F])(implicit F: Sync[F]): OptionT[F, Response[F]] = OptionT { getHandler(instrumentation)(request).use { handler => @@ -63,21 +63,21 @@ object KamonSupport { } private def processRequest[F[_]]( - requestHandler: RequestHandler + requestHandler: RequestHandler )(implicit F: Sync[F]): Resource[F, RequestHandler] = Resource.make(F.delay(requestHandler.requestReceived()))(h => F.delay(h.responseSent()) ) private def withContext[F[_]]( - requestHandler: RequestHandler + requestHandler: RequestHandler )(implicit F: Sync[F]): Resource[F, Storage.Scope] = Resource.make(F.delay(Kamon.storeContext(requestHandler.context)))(scope => F.delay(scope.close()) ) private def getHandler[F[_]]( - instrumentation: HttpServerInstrumentation + instrumentation: HttpServerInstrumentation )(request: Request[F])(implicit F: Sync[F]): Resource[F, RequestHandler] = for { handler <- Resource.eval( @@ -88,9 +88,9 @@ object KamonSupport { } yield handler private def kamonServiceHandler[F[_]]( - requestHandler: RequestHandler, - e: Either[Throwable, Option[Response[F]]], - settings: HttpServerInstrumentation.Settings + requestHandler: RequestHandler, + e: Either[Throwable, Option[Response[F]]], + settings: HttpServerInstrumentation.Settings )(implicit F: Sync[F]): F[Option[Response[F]]] = e match { case Left(e) => diff --git a/instrumentation/kamon-http4s-1.0/src/main/scala/kamon/http4s/package.scala b/instrumentation/kamon-http4s-1.0/src/main/scala/kamon/http4s/package.scala index a02b46e5c..8fc69f9a6 100644 --- a/instrumentation/kamon-http4s-1.0/src/main/scala/kamon/http4s/package.scala +++ b/instrumentation/kamon-http4s-1.0/src/main/scala/kamon/http4s/package.scala @@ -52,7 +52,7 @@ package object http4s { } def getResponseBuilder[F[_]]( - response: Response[F] + response: Response[F] ): ResponseBuilder[Response[F]] = new HttpMessage.ResponseBuilder[Response[F]] { private var _headers = response.headers @@ -66,7 +66,7 @@ package object http4s { } def getRequestBuilder[F[_]]( - request: Request[F] + request: Request[F] ): HttpMessage.RequestBuilder[Request[F]] = new HttpMessage.RequestBuilder[Request[F]] { private var _headers = request.headers diff --git a/instrumentation/kamon-http4s-1.0/src/test/scala/kamon/http4s/HttpMetricsSpec.scala b/instrumentation/kamon-http4s-1.0/src/test/scala/kamon/http4s/HttpMetricsSpec.scala index eca9867f4..4174db8b3 100644 --- a/instrumentation/kamon-http4s-1.0/src/test/scala/kamon/http4s/HttpMetricsSpec.scala +++ b/instrumentation/kamon-http4s-1.0/src/test/scala/kamon/http4s/HttpMetricsSpec.scala @@ -70,7 +70,7 @@ class HttpMetricsSpec ) def withServerAndClient[A]( - f: (Server, Client[IO], HttpServerMetrics.HttpServerInstruments) => IO[A] + f: (Server, Client[IO], HttpServerMetrics.HttpServerInstruments) => IO[A] ): A = (srv, client, metrics).tupled.use(f.tupled).unsafeRunSync() @@ -84,7 +84,7 @@ class HttpMetricsSpec } private def get[F[_]: Concurrent]( - path: String + path: String )(server: Server, client: Client[F]): F[String] = { client.expect[String](s"http://127.0.0.1:${server.address.port}$path") } diff --git a/instrumentation/kamon-http4s-1.0/src/test/scala/kamon/http4s/ServerInstrumentationSpec.scala b/instrumentation/kamon-http4s-1.0/src/test/scala/kamon/http4s/ServerInstrumentationSpec.scala index 30422a48d..0e87aa9a4 100644 --- a/instrumentation/kamon-http4s-1.0/src/test/scala/kamon/http4s/ServerInstrumentationSpec.scala +++ b/instrumentation/kamon-http4s-1.0/src/test/scala/kamon/http4s/ServerInstrumentationSpec.scala @@ -71,7 +71,7 @@ class ServerInstrumentationSpec (srv, client).tupled.use(f.tupled).unsafeRunSync() private def getResponse[F[_]: Concurrent]( - path: String + path: String )(server: Server, client: Client[F]): F[(String, Headers)] = { client.get(s"http://127.0.0.1:${server.address.port}$path") { r => r.bodyText.compile.toList.map(_.mkString).map(_ -> r.headers) diff --git a/instrumentation/kamon-instrumentation-common/src/main/scala-2.12/scala/annotation/static.scala b/instrumentation/kamon-instrumentation-common/src/main/scala-2.12/scala/annotation/static.scala index 0ebf81c1d..2d336e2e3 100644 --- a/instrumentation/kamon-instrumentation-common/src/main/scala-2.12/scala/annotation/static.scala +++ b/instrumentation/kamon-instrumentation-common/src/main/scala-2.12/scala/annotation/static.scala @@ -1,4 +1,4 @@ package scala.annotation import scala.annotation.meta._ -final class static extends StaticAnnotation \ No newline at end of file +final class static extends StaticAnnotation diff --git a/instrumentation/kamon-instrumentation-common/src/main/scala/kamon/instrumentation/context/CaptureCurrentContext.scala b/instrumentation/kamon-instrumentation-common/src/main/scala/kamon/instrumentation/context/CaptureCurrentContext.scala index a479f9667..4313bbd5e 100644 --- a/instrumentation/kamon-instrumentation-common/src/main/scala/kamon/instrumentation/context/CaptureCurrentContext.scala +++ b/instrumentation/kamon-instrumentation-common/src/main/scala/kamon/instrumentation/context/CaptureCurrentContext.scala @@ -24,7 +24,7 @@ import kanela.agent.libs.net.bytebuddy.asm.Advice * Advise that copies the current Context from Kamon into a HasContext instance when the advised method starts * executing. */ -class CaptureCurrentContextOnEnter private() +class CaptureCurrentContextOnEnter private () object CaptureCurrentContextOnEnter { @Advice.OnMethodEnter diff --git a/instrumentation/kamon-instrumentation-common/src/main/scala/kamon/instrumentation/context/CaptureCurrentTimestamp.scala b/instrumentation/kamon-instrumentation-common/src/main/scala/kamon/instrumentation/context/CaptureCurrentTimestamp.scala index 0da000c7e..93d3a6725 100644 --- a/instrumentation/kamon-instrumentation-common/src/main/scala/kamon/instrumentation/context/CaptureCurrentTimestamp.scala +++ b/instrumentation/kamon-instrumentation-common/src/main/scala/kamon/instrumentation/context/CaptureCurrentTimestamp.scala @@ -19,11 +19,12 @@ package kamon.instrumentation.context import kanela.agent.libs.net.bytebuddy.asm.Advice import scala.annotation.static + /** * Advise that copies the current System.nanoTime into a HasTimestamp instance when the advised method starts * executing. */ -class CaptureCurrentTimestampOnEnter private() +class CaptureCurrentTimestampOnEnter private () object CaptureCurrentTimestampOnEnter { @Advice.OnMethodEnter diff --git a/instrumentation/kamon-instrumentation-common/src/main/scala/kamon/instrumentation/context/HasContext.scala b/instrumentation/kamon-instrumentation-common/src/main/scala/kamon/instrumentation/context/HasContext.scala index 673ed1429..b85f3907f 100644 --- a/instrumentation/kamon-instrumentation-common/src/main/scala/kamon/instrumentation/context/HasContext.scala +++ b/instrumentation/kamon-instrumentation-common/src/main/scala/kamon/instrumentation/context/HasContext.scala @@ -48,7 +48,7 @@ object HasContext { class Mixin(@transient private var _context: Context) extends HasContext { override def context: Context = - if(_context != null) _context else Context.Empty + if (_context != null) _context else Context.Empty override def setContext(context: Context): Unit = _context = context @@ -60,7 +60,7 @@ object HasContext { class VolatileMixin(@transient @volatile private var _context: Context) extends HasContext { override def context: Context = - if(_context != null) _context else Context.Empty + if (_context != null) _context else Context.Empty override def setContext(context: Context): Unit = _context = context @@ -100,4 +100,4 @@ object HasContext { setContext(Kamon.currentContext()) } -} \ No newline at end of file +} diff --git a/instrumentation/kamon-instrumentation-common/src/main/scala/kamon/instrumentation/context/HasTimestamp.scala b/instrumentation/kamon-instrumentation-common/src/main/scala/kamon/instrumentation/context/HasTimestamp.scala index ae1850427..19a9d1d02 100644 --- a/instrumentation/kamon-instrumentation-common/src/main/scala/kamon/instrumentation/context/HasTimestamp.scala +++ b/instrumentation/kamon-instrumentation-common/src/main/scala/kamon/instrumentation/context/HasTimestamp.scala @@ -75,7 +75,6 @@ object HasTimestamp { _timestamp = timestamp } - /** * HasTimestamp implementation that keeps the timestamp in a mutable field and initializes it with the result of * calling System.nanoTime() when the instrumented instance is initialized. @@ -111,4 +110,4 @@ object HasTimestamp { def initialize(): Unit = setTimestamp(System.nanoTime()) } -} \ No newline at end of file +} diff --git a/instrumentation/kamon-instrumentation-common/src/main/scala/kamon/instrumentation/context/InvokeWithCapturedContext.scala b/instrumentation/kamon-instrumentation-common/src/main/scala/kamon/instrumentation/context/InvokeWithCapturedContext.scala index c1a0e41f1..3c4840afd 100644 --- a/instrumentation/kamon-instrumentation-common/src/main/scala/kamon/instrumentation/context/InvokeWithCapturedContext.scala +++ b/instrumentation/kamon-instrumentation-common/src/main/scala/kamon/instrumentation/context/InvokeWithCapturedContext.scala @@ -18,14 +18,14 @@ package kamon package instrumentation package context - import kamon.context.Storage import kanela.agent.libs.net.bytebuddy.asm.Advice import scala.annotation.static + /** * Advice that sets the Context from a HasContext instance as the current Context while the advised method is invoked. */ -class InvokeWithCapturedContext private() +class InvokeWithCapturedContext private () object InvokeWithCapturedContext { @Advice.OnMethodEnter diff --git a/instrumentation/kamon-instrumentation-common/src/main/scala/kamon/instrumentation/http/HttpClientInstrumentation.scala b/instrumentation/kamon-instrumentation-common/src/main/scala/kamon/instrumentation/http/HttpClientInstrumentation.scala index 25bff42eb..f31dc8dd9 100644 --- a/instrumentation/kamon-instrumentation-common/src/main/scala/kamon/instrumentation/http/HttpClientInstrumentation.scala +++ b/instrumentation/kamon-instrumentation-common/src/main/scala/kamon/instrumentation/http/HttpClientInstrumentation.scala @@ -52,7 +52,10 @@ trait HttpClientInstrumentation { * instance contained in the handler replaces the original HTTP request sent by the user, since the updated HTTP * request will have all the required additional headers to enable context propagation and distributed tracing. */ - def createHandler[T](request: HttpMessage.RequestBuilder[T], context: Context): HttpClientInstrumentation.RequestHandler[T] + def createHandler[T]( + request: HttpMessage.RequestBuilder[T], + context: Context + ): HttpClientInstrumentation.RequestHandler[T] /** * Returns the settings currently controlling the HTTP client instrumentation. The effective settings will be taken @@ -110,11 +113,16 @@ object HttpClientInstrumentation { private class Default(val settings: Settings, component: String) extends HttpClientInstrumentation { private val _propagation = Kamon.httpPropagation(settings.propagationChannel) .getOrElse { - _log.warn(s"Could not find HTTP propagation [${settings.propagationChannel}], falling back to the default HTTP propagation") + _log.warn( + s"Could not find HTTP propagation [${settings.propagationChannel}], falling back to the default HTTP propagation" + ) Kamon.defaultHttpPropagation() } - override def createHandler[T](requestBuilder: HttpMessage.RequestBuilder[T], context: Context): RequestHandler[T] = { + override def createHandler[T]( + requestBuilder: HttpMessage.RequestBuilder[T], + context: Context + ): RequestHandler[T] = { val shouldCreateSpan = !Kamon.currentSpan().isEmpty || settings.startTrace val requestSpan: Span = { if (settings.enableContextPropagation && shouldCreateSpan) { @@ -139,7 +147,7 @@ object HttpClientInstrumentation { override def processResponse(response: HttpMessage.Response): Unit = { val statusCode = response.statusCode - if(statusCode >= 500) { + if (statusCode >= 500) { span.fail("Request failed with HTTP Status Code " + statusCode) } @@ -154,7 +162,7 @@ object HttpClientInstrumentation { .clientSpanBuilder(settings.operationNameSettings.operationName(requestMessage), component) .context(context) - if(!settings.enableSpanMetrics) + if (!settings.enableSpanMetrics) span.doNotTrackMetrics() SpanTagger.tag(span, TagKeys.HttpUrl, requestMessage.url, settings.urlTagMode) @@ -171,7 +179,7 @@ object HttpClientInstrumentation { } } - final case class Settings ( + final case class Settings( enableContextPropagation: Boolean, propagationChannel: String, enableTracing: Boolean, @@ -196,7 +204,7 @@ object HttpClientInstrumentation { val enablePropagation = config.getBoolean("propagation.enabled") val propagationChannel = config.getString("propagation.channel") - // Tracing settings + // Tracing settings val enableTracing = config.getBoolean("tracing.enabled") val enableSpanMetrics = config.getBoolean("tracing.span-metrics") val urlTagMode = TagMode.from(config.getString("tracing.tags.url")) diff --git a/instrumentation/kamon-instrumentation-common/src/main/scala/kamon/instrumentation/http/HttpMessage.scala b/instrumentation/kamon-instrumentation-common/src/main/scala/kamon/instrumentation/http/HttpMessage.scala index 8f5675957..25af937bf 100644 --- a/instrumentation/kamon-instrumentation-common/src/main/scala/kamon/instrumentation/http/HttpMessage.scala +++ b/instrumentation/kamon-instrumentation-common/src/main/scala/kamon/instrumentation/http/HttpMessage.scala @@ -90,4 +90,4 @@ object HttpMessage { */ trait ResponseBuilder[Message] extends Response with Builder[Message] -} \ No newline at end of file +} diff --git a/instrumentation/kamon-instrumentation-common/src/main/scala/kamon/instrumentation/http/HttpOperationNameGenerator.scala b/instrumentation/kamon-instrumentation-common/src/main/scala/kamon/instrumentation/http/HttpOperationNameGenerator.scala index 7f0693866..41a16050d 100644 --- a/instrumentation/kamon-instrumentation-common/src/main/scala/kamon/instrumentation/http/HttpOperationNameGenerator.scala +++ b/instrumentation/kamon-instrumentation-common/src/main/scala/kamon/instrumentation/http/HttpOperationNameGenerator.scala @@ -50,7 +50,6 @@ object HttpOperationNameGenerator { Option(request.host).map(h => s"$h:${request.port}") } - /** * Uses the request HTTP Method to assign a name. */ diff --git a/instrumentation/kamon-instrumentation-common/src/main/scala/kamon/instrumentation/http/HttpServerInstrumentation.scala b/instrumentation/kamon-instrumentation-common/src/main/scala/kamon/instrumentation/http/HttpServerInstrumentation.scala index 8fd726016..641ac508f 100644 --- a/instrumentation/kamon-instrumentation-common/src/main/scala/kamon/instrumentation/http/HttpServerInstrumentation.scala +++ b/instrumentation/kamon-instrumentation-common/src/main/scala/kamon/instrumentation/http/HttpServerInstrumentation.scala @@ -34,7 +34,6 @@ import org.slf4j.LoggerFactory import scala.util.Try - /** * HTTP Server instrumentation handler that takes care of context propagation, distributed tracing and HTTP server * metrics. Instances can be created by using the `HttpServerInstrumentation.from` method with the desired @@ -83,7 +82,10 @@ trait HttpServerInstrumentation { * the sampling decision is deferred, the returned Span will have an Unknown sampling decision and the * instrumentation or user code must call Span.takeSamplingDecision() on the Span. */ - def createHandler(request: HttpMessage.Request, deferSamplingDecision: Boolean): HttpServerInstrumentation.RequestHandler + def createHandler( + request: HttpMessage.Request, + deferSamplingDecision: Boolean + ): HttpServerInstrumentation.RequestHandler /** * Signals that a new HTTP connection has been opened. @@ -132,7 +134,7 @@ trait HttpServerInstrumentation { object HttpServerInstrumentation { private val _log = LoggerFactory.getLogger(classOf[Default]) - + /** * Handler associated to the processing of a single request. The instrumentation code using this class is responsible * of creating a dedicated `HttpServer.RequestHandler` instance for each received request and invoking the @@ -189,7 +191,6 @@ object HttpServerInstrumentation { } - /** * Creates a new HTTP Server Instrumentation, configured with the settings on the provided config path. If any of the * settings are missing they will be taken from the default HTTP server instrumentation. All HTTP server variants @@ -209,25 +210,28 @@ object HttpServerInstrumentation { private class Default(val settings: Settings, component: String, val interface: String, val port: Int) extends HttpServerInstrumentation { - private val _metrics = if(settings.enableServerMetrics) Some(HttpServerMetrics.of(component, interface, port)) else None + private val _metrics = + if (settings.enableServerMetrics) Some(HttpServerMetrics.of(component, interface, port)) else None private val _log = LoggerFactory.getLogger(classOf[Default]) private val _propagation = Kamon.httpPropagation(settings.propagationChannel) .getOrElse { - _log.warn(s"Could not find HTTP propagation [${settings.propagationChannel}], falling back to the default HTTP propagation") + _log.warn( + s"Could not find HTTP propagation [${settings.propagationChannel}], falling back to the default HTTP propagation" + ) Kamon.defaultHttpPropagation() } override def createHandler(request: HttpMessage.Request, deferSamplingDecision: Boolean): RequestHandler = { - val incomingContext = if(settings.enableContextPropagation) + val incomingContext = if (settings.enableContextPropagation) _propagation.read(request) else Context.Empty - val requestSpan = if(settings.enableTracing) + val requestSpan = if (settings.enableTracing) buildServerSpan(incomingContext, request, deferSamplingDecision) else Span.Empty - val handlerContext = if(!requestSpan.isEmpty) + val handlerContext = if (!requestSpan.isEmpty) incomingContext.withEntry(Span.Key, requestSpan) else incomingContext @@ -243,7 +247,7 @@ object HttpServerInstrumentation { requestSpan override def requestReceived(receivedBytes: Long): RequestHandler = { - if(receivedBytes >= 0) { + if (receivedBytes >= 0) { _metrics.foreach { httpServerMetrics => httpServerMetrics.requestSize.record(receivedBytes) } @@ -252,20 +256,25 @@ object HttpServerInstrumentation { this } - override def buildResponse[HttpResponse](response: HttpMessage.ResponseBuilder[HttpResponse], context: Context): HttpResponse = { + override def buildResponse[HttpResponse]( + response: HttpMessage.ResponseBuilder[HttpResponse], + context: Context + ): HttpResponse = { _metrics.foreach { httpServerMetrics => httpServerMetrics.countCompletedRequest(response.statusCode) } - if(!span.isEmpty) { + if (!span.isEmpty) { settings.traceIDResponseHeader.foreach(traceIDHeader => response.write(traceIDHeader, span.trace.id.string)) settings.spanIDResponseHeader.foreach(spanIDHeader => response.write(spanIDHeader, span.id.string)) - settings.httpServerResponseHeaderGenerator.headers(handlerContext).foreach(header => response.write(header._1, header._2)) - + settings.httpServerResponseHeaderGenerator.headers(handlerContext).foreach(header => + response.write(header._1, header._2) + ) + SpanTagger.tag(span, TagKeys.HttpStatusCode, response.statusCode, settings.statusCodeTagMode) val statusCode = response.statusCode - if(statusCode >= 500) { + if (statusCode >= 500) { span.fail("Request failed with HTTP Status Code " + response.statusCode) } } @@ -277,7 +286,7 @@ object HttpServerInstrumentation { _metrics.foreach { httpServerMetrics => httpServerMetrics.activeRequests.decrement() - if(sentBytes >= 0) + if (sentBytes >= 0) httpServerMetrics.responseSize.record(sentBytes) } @@ -296,10 +305,10 @@ object HttpServerInstrumentation { _metrics.foreach { httpServerMetrics => httpServerMetrics.openConnections.decrement() - if(lifetime != Duration.ZERO) + if (lifetime != Duration.ZERO) httpServerMetrics.connectionLifetime.record(lifetime.toNanos) - if(handledRequests > 0) + if (handledRequests > 0) httpServerMetrics.connectionUsage.record(handledRequests) } } @@ -310,20 +319,23 @@ object HttpServerInstrumentation { } } - - private def buildServerSpan(context: Context, request: HttpMessage.Request, deferSamplingDecision: Boolean): Span = { + private def buildServerSpan( + context: Context, + request: HttpMessage.Request, + deferSamplingDecision: Boolean + ): Span = { val span = Kamon.serverSpanBuilder(settings.operationNameSettings.operationName(request), component) span.context(context) - if(!settings.enableSpanMetrics) + if (!settings.enableSpanMetrics) span.doNotTrackMetrics() - if(deferSamplingDecision) + if (deferSamplingDecision) span.samplingDecision(SamplingDecision.Unknown) for { traceIdTag <- settings.traceIDTag; customTraceID <- context.getTag(option(traceIdTag)) } { val identifier = Kamon.identifierScheme.traceIdFactory.from(customTraceID) - if(!identifier.isEmpty) + if (!identifier.isEmpty) span.traceId(identifier) } @@ -336,12 +348,10 @@ object HttpServerInstrumentation { .foreach(tagValue => SpanTagger.tag(span, tagName, tagValue, mode)) } - span.start() } } - final case class Settings( enableContextPropagation: Boolean, propagationChannel: String, @@ -359,7 +369,7 @@ object HttpServerInstrumentation { unhandledOperationName: String, operationMappings: Map[Filter.Glob, String], operationNameGenerator: HttpOperationNameGenerator, - httpServerResponseHeaderGenerator:HttpServerResponseHeaderGenerator + httpServerResponseHeaderGenerator: HttpServerResponseHeaderGenerator ) { val operationNameSettings = OperationNameSettings(defaultOperationName, operationMappings, operationNameGenerator) } @@ -367,7 +377,7 @@ object HttpServerInstrumentation { object Settings { def from(config: Config): Settings = { - def optionalString(value: String): Option[String] = if(value.equalsIgnoreCase("none")) None else Some(value) + def optionalString(value: String): Option[String] = if (value.equalsIgnoreCase("none")) None else Some(value) // Context propagation settings val enablePropagation = config.getBoolean("propagation.enabled") @@ -393,20 +403,20 @@ object HttpServerInstrumentation { val httpServerResponseHeaderGenerator: Try[HttpServerResponseHeaderGenerator] = Try { config.getString("tracing.response-headers.headers-generator") match { case "none" => DefaultHttpServerResponseHeaderGenerator - case fqcn => ClassLoading.createInstance[HttpServerResponseHeaderGenerator](fqcn) + case fqcn => ClassLoading.createInstance[HttpServerResponseHeaderGenerator](fqcn) } } recover { case t: Throwable => _log.warn("Failed to create an HTTP Server Response Header Generator, falling back to the default no-op", t) DefaultHttpServerResponseHeaderGenerator } - + val defaultOperationName = config.getString("tracing.operations.default") val operationNameGenerator: Try[HttpOperationNameGenerator] = Try { config.getString("tracing.operations.name-generator") match { case "default" => new HttpOperationNameGenerator.Static(defaultOperationName) - case "method" => HttpOperationNameGenerator.Method - case fqcn => ClassLoading.createInstance[HttpOperationNameGenerator](fqcn) + case "method" => HttpOperationNameGenerator.Method + case fqcn => ClassLoading.createInstance[HttpOperationNameGenerator](fqcn) } } recover { case t: Throwable => diff --git a/instrumentation/kamon-instrumentation-common/src/main/scala/kamon/instrumentation/http/HttpServerMetrics.scala b/instrumentation/kamon-instrumentation-common/src/main/scala/kamon/instrumentation/http/HttpServerMetrics.scala index 2d1fc60e8..ea9c8e7d9 100644 --- a/instrumentation/kamon-instrumentation-common/src/main/scala/kamon/instrumentation/http/HttpServerMetrics.scala +++ b/instrumentation/kamon-instrumentation-common/src/main/scala/kamon/instrumentation/http/HttpServerMetrics.scala @@ -27,39 +27,39 @@ object HttpServerMetrics { private val _logger = LoggerFactory.getLogger("kamon.instrumentation.http.HttpServerMetrics") - val CompletedRequests = Kamon.counter ( + val CompletedRequests = Kamon.counter( name = "http.server.requests", description = "Number of completed requests per status code" ) - val ActiveRequests = Kamon.rangeSampler ( + val ActiveRequests = Kamon.rangeSampler( name = "http.server.request.active", description = "Number of requests being processed simultaneously at any point in time" ) - val RequestSize = Kamon.histogram ( + val RequestSize = Kamon.histogram( name = "http.server.request.size", description = "Request size distribution (including headers and body) for all requests received by the server", unit = information.bytes ) - val ResponseSize = Kamon.histogram ( + val ResponseSize = Kamon.histogram( name = "http.server.response.size", description = "Response size distribution (including headers and body) for all responses served by the server", unit = information.bytes ) - val ConnectionLifetime = Kamon.timer ( + val ConnectionLifetime = Kamon.timer( name = "http.server.connection.lifetime", description = "Tracks the time elapsed between connection creation and connection close" ) - val ConnectionUsage = Kamon.histogram ( + val ConnectionUsage = Kamon.histogram( name = "http.server.connection.usage", description = "Distribution of number of requests handled per connection during their entire lifetime" ) - val OpenConnections = Kamon.rangeSampler ( + val OpenConnections = Kamon.rangeSampler( name = "http.server.connection.open", description = "Number of open connections" ) @@ -85,15 +85,15 @@ object HttpServerMetrics { * Increments the appropriate response counter depending on the the status code. */ def countCompletedRequest(statusCode: Int): Unit = { - if(statusCode >= 200 && statusCode <= 299) + if (statusCode >= 200 && statusCode <= 299) requestsSuccessful.increment() - else if(statusCode >= 500 && statusCode <= 599) + else if (statusCode >= 500 && statusCode <= 599) requestsServerError.increment() - else if(statusCode >= 400 && statusCode <= 499) + else if (statusCode >= 400 && statusCode <= 499) requestsClientError.increment() - else if(statusCode >= 300 && statusCode <= 399) + else if (statusCode >= 300 && statusCode <= 399) requestsRedirection.increment() - else if(statusCode >= 100 && statusCode <= 199) + else if (statusCode >= 100 && statusCode <= 199) requestsInformational.increment() else { _logger.warn("Unknown HTTP status code {} found when recording HTTP server metrics", statusCode.toString) @@ -105,7 +105,7 @@ object HttpServerMetrics { * Creates a new HttpServer.Metrics instance with the provided component, interface and port tags. */ def of(component: String, interface: String, port: Int): HttpServerInstruments = - new HttpServerInstruments ( + new HttpServerInstruments( TagSet.builder() .add(TagKeys.Component, component) .add(TagKeys.Interface, interface) diff --git a/instrumentation/kamon-instrumentation-common/src/main/scala/kamon/instrumentation/http/HttpServerResponseHeaderGenerator.scala b/instrumentation/kamon-instrumentation-common/src/main/scala/kamon/instrumentation/http/HttpServerResponseHeaderGenerator.scala index 46d180308..0d575f71f 100644 --- a/instrumentation/kamon-instrumentation-common/src/main/scala/kamon/instrumentation/http/HttpServerResponseHeaderGenerator.scala +++ b/instrumentation/kamon-instrumentation-common/src/main/scala/kamon/instrumentation/http/HttpServerResponseHeaderGenerator.scala @@ -22,20 +22,22 @@ import kamon.context.Context * Allows for adding custom HTTP headers to the responses */ trait HttpServerResponseHeaderGenerator { + /** * Returns the headers (name/value) to be appended to the response * @param context The context for the current request * @return */ - def headers(context:Context):Map[String, String] + def headers(context: Context): Map[String, String] } /** * Default implementation of the ''HttpServerResponseHeaderGenerator'' */ object DefaultHttpServerResponseHeaderGenerator extends HttpServerResponseHeaderGenerator { + /** * Always returns empty Map */ - def headers(context:Context):Map[String, String] = Map.empty + def headers(context: Context): Map[String, String] = Map.empty } diff --git a/instrumentation/kamon-instrumentation-common/src/main/scala/kamon/instrumentation/http/OperationNameSettings.scala b/instrumentation/kamon-instrumentation-common/src/main/scala/kamon/instrumentation/http/OperationNameSettings.scala index cf33ab1c0..e1122890d 100644 --- a/instrumentation/kamon-instrumentation-common/src/main/scala/kamon/instrumentation/http/OperationNameSettings.scala +++ b/instrumentation/kamon-instrumentation-common/src/main/scala/kamon/instrumentation/http/OperationNameSettings.scala @@ -22,9 +22,10 @@ import org.slf4j.LoggerFactory import scala.util.Try final case class OperationNameSettings( - defaultOperationName: String, - operationMappings: Map[Filter.Glob, String], - operationNameGenerator: HttpOperationNameGenerator) { + defaultOperationName: String, + operationMappings: Map[Filter.Glob, String], + operationNameGenerator: HttpOperationNameGenerator +) { private val logger = LoggerFactory.getLogger(classOf[OperationNameSettings]) @@ -32,15 +33,15 @@ final case class OperationNameSettings( Try { val requestPath = request.path - //first apply any mappings rules + // first apply any mappings rules val customMapping = operationMappings.collectFirst { case (pattern, operationName) if pattern.accept(requestPath) => operationName } orElse { - //fallback to use any configured name generator + // fallback to use any configured name generator operationNameGenerator.name(request) } customMapping.getOrElse(defaultOperationName) - } getOrElse(defaultOperationName) + } getOrElse (defaultOperationName) } } diff --git a/instrumentation/kamon-instrumentation-common/src/main/scala/kamon/instrumentation/package.scala b/instrumentation/kamon-instrumentation-common/src/main/scala/kamon/instrumentation/package.scala index 0355a6466..f6d5b8e9f 100644 --- a/instrumentation/kamon-instrumentation-common/src/main/scala/kamon/instrumentation/package.scala +++ b/instrumentation/kamon-instrumentation-common/src/main/scala/kamon/instrumentation/package.scala @@ -30,18 +30,23 @@ package object instrumentation { * underlying implementation is expecting a class with static methods, which can only be provided by plain companion * objects; any nested companion object will not be appropriately picked up. */ - def advise[A](method: Junction[MethodDescription], advice: A)(implicit singletonEvidence: A <:< Singleton): InstrumentationBuilder.Target + def advise[A](method: Junction[MethodDescription], advice: A)(implicit + singletonEvidence: A <:< Singleton + ): InstrumentationBuilder.Target } - implicit def adviseWithCompanionObject(target: InstrumentationBuilder.Target): AdviseWithCompanionObject = new AdviseWithCompanionObject { + implicit def adviseWithCompanionObject(target: InstrumentationBuilder.Target): AdviseWithCompanionObject = + new AdviseWithCompanionObject { - override def advise[A](method: Junction[MethodDescription], advice: A)(implicit singletonEvidence: A <:< Singleton): InstrumentationBuilder.Target = { - // Companion object instances always have the '$' sign at the end of their class name, we must remove it to get - // to the class that exposes the static methods. - val className = advice.getClass.getName.dropRight(1) - val adviseClass = Class.forName(className, true, advice.getClass.getClassLoader) + override def advise[A](method: Junction[MethodDescription], advice: A)(implicit + singletonEvidence: A <:< Singleton + ): InstrumentationBuilder.Target = { + // Companion object instances always have the '$' sign at the end of their class name, we must remove it to get + // to the class that exposes the static methods. + val className = advice.getClass.getName.dropRight(1) + val adviseClass = Class.forName(className, true, advice.getClass.getClassLoader) - target.advise(method, adviseClass) + target.advise(method, adviseClass) + } } - } } diff --git a/instrumentation/kamon-instrumentation-common/src/main/scala/kamon/instrumentation/trace/Tagger.scala b/instrumentation/kamon-instrumentation-common/src/main/scala/kamon/instrumentation/trace/Tagger.scala index e1f105825..4674f57b1 100644 --- a/instrumentation/kamon-instrumentation-common/src/main/scala/kamon/instrumentation/trace/Tagger.scala +++ b/instrumentation/kamon-instrumentation-common/src/main/scala/kamon/instrumentation/trace/Tagger.scala @@ -71,8 +71,8 @@ object SpanTagger { def from(value: String): TagMode = value.toLowerCase match { case "metric" => TagMode.Metric - case "span" => TagMode.Span - case _ => TagMode.Off + case "span" => TagMode.Span + case _ => TagMode.Off } } } diff --git a/instrumentation/kamon-instrumentation-common/src/test/scala/kamon/instrumentation/context/ContextInstrumentationSpec.scala b/instrumentation/kamon-instrumentation-common/src/test/scala/kamon/instrumentation/context/ContextInstrumentationSpec.scala index b71510612..5bf0ea90c 100644 --- a/instrumentation/kamon-instrumentation-common/src/test/scala/kamon/instrumentation/context/ContextInstrumentationSpec.scala +++ b/instrumentation/kamon-instrumentation-common/src/test/scala/kamon/instrumentation/context/ContextInstrumentationSpec.scala @@ -99,7 +99,6 @@ object ContextInstrumentationSpec { .advise(method("doSomething"), CaptureCurrentContextOnExit) .advise(method("doWork"), InvokeWithCapturedContext) - onType("kamon.instrumentation.context.ContextInstrumentationSpec$TargetWithInitializer") .mixin(classOf[HasContext.MixinWithInitializer]) .advise(method("doSomething"), CaptureCurrentContextOnExit) diff --git a/instrumentation/kamon-instrumentation-common/src/test/scala/kamon/instrumentation/http/HttpClientInstrumentationSpec.scala b/instrumentation/kamon-instrumentation-common/src/test/scala/kamon/instrumentation/http/HttpClientInstrumentationSpec.scala index f952945e8..2f506c31f 100644 --- a/instrumentation/kamon-instrumentation-common/src/test/scala/kamon/instrumentation/http/HttpClientInstrumentationSpec.scala +++ b/instrumentation/kamon-instrumentation-common/src/test/scala/kamon/instrumentation/http/HttpClientInstrumentationSpec.scala @@ -1,6 +1,5 @@ package kamon.instrumentation.http - import com.typesafe.config.ConfigFactory import kamon.Kamon import kamon.context.Context @@ -22,11 +21,18 @@ class HttpClientInstrumentationSpec extends AnyWordSpec with Matchers with Instr "configured for context propagation" should { "write context entries and tags to the outgoing request" in { val context = Context.of(TagSet.of("example", "tag")) - val handler = httpClient().createHandler(fakeRequest("http://localhost:8080/", "/", "GET", Map( - "some-header" -> "tag=value;none=0011223344556677;", - "some-other-header" -> "0011223344556677" - )), context) - + val handler = httpClient().createHandler( + fakeRequest( + "http://localhost:8080/", + "/", + "GET", + Map( + "some-header" -> "tag=value;none=0011223344556677;", + "some-other-header" -> "0011223344556677" + ) + ), + context + ) handler.request.read("context-tags").value shouldBe "example=tag;upstream.name=kamon-application;" handler.request.readAll().keys should contain allOf ( @@ -66,12 +72,16 @@ class HttpClientInstrumentationSpec extends AnyWordSpec with Matchers with Instr } "record span metrics when enabled" in { - val handler = httpClient().createHandler(fakeRequest("http://localhost:8080/", "/", "GET", Map.empty), Context.Empty) + val handler = + httpClient().createHandler(fakeRequest("http://localhost:8080/", "/", "GET", Map.empty), Context.Empty) handler.span.isTrackingMetrics() shouldBe true } "not record span metrics when disabled" in { - val handler = noSpanMetricsHttpClient().createHandler(fakeRequest("http://localhost:8080/", "/", "GET", Map.empty), Context.Empty) + val handler = noSpanMetricsHttpClient().createHandler( + fakeRequest("http://localhost:8080/", "/", "GET", Map.empty), + Context.Empty + ) handler.span.isTrackingMetrics() shouldBe false } @@ -87,7 +97,10 @@ class HttpClientInstrumentationSpec extends AnyWordSpec with Matchers with Instr } "honour user provided operation name mappings" in { - val handler = httpClient().createHandler(fakeRequest("http://localhost:8080/", "/events/123/rsvps", "GET", Map.empty), Context.Empty) + val handler = httpClient().createHandler( + fakeRequest("http://localhost:8080/", "/events/123/rsvps", "GET", Map.empty), + Context.Empty + ) handler.processResponse(fakeResponse(200)) val span = handler.span @@ -99,7 +112,10 @@ class HttpClientInstrumentationSpec extends AnyWordSpec with Matchers with Instr } "fallback to the default operation name when there is a problem while figuring out a custom operation name" in { - val handler = httpClient().createHandler(fakeRequest("http://localhost:8080/", "/fail-operation-name", "GET", Map.empty), Context.Empty) + val handler = httpClient().createHandler( + fakeRequest("http://localhost:8080/", "/fail-operation-name", "GET", Map.empty), + Context.Empty + ) handler.processResponse(fakeResponse(200)) val span = handler.span @@ -115,7 +131,8 @@ class HttpClientInstrumentationSpec extends AnyWordSpec with Matchers with Instr "not write any context to the outgoing requests" in { val parent = parentSpan() val context = Context.of(Span.Key, parent, TagSet.of("example", "tag")) - val handler = noopHttpClient().createHandler(fakeRequest("http://localhost:8080/", "/", "GET", Map.empty), context) + val handler = + noopHttpClient().createHandler(fakeRequest("http://localhost:8080/", "/", "GET", Map.empty), context) handler.request.readAll() shouldBe empty } @@ -123,7 +140,8 @@ class HttpClientInstrumentationSpec extends AnyWordSpec with Matchers with Instr "not create any span to represent the client request" in { val parent = parentSpan() val context = Context.of(Span.Key, parent, TagSet.of("example", "tag")) - val handler = noopHttpClient().createHandler(fakeRequest("http://localhost:8080/", "/", "GET", Map.empty), context) + val handler = + noopHttpClient().createHandler(fakeRequest("http://localhost:8080/", "/", "GET", Map.empty), context) handler.span shouldBe empty } @@ -136,18 +154,26 @@ class HttpClientInstrumentationSpec extends AnyWordSpec with Matchers with Instr HttpClientInstrumentation.from(ConfigFactory.empty(), TestComponent) def noSpanMetricsHttpClient(): HttpClientInstrumentation = - HttpClientInstrumentation.from( Kamon.config().getConfig("kamon.instrumentation.http-client.no-span-metrics"), TestComponent) + HttpClientInstrumentation.from( + Kamon.config().getConfig("kamon.instrumentation.http-client.no-span-metrics"), + TestComponent + ) def noopHttpClient(): HttpClientInstrumentation = - HttpClientInstrumentation.from( Kamon.config().getConfig("kamon.instrumentation.http-client.noop"), TestComponent) - - def fakeRequest(requestUrl: String, requestPath: String, requestMethod: String, initialHeaders: Map[String, String]): HttpMessage.RequestBuilder[HttpMessage.Request] = + HttpClientInstrumentation.from(Kamon.config().getConfig("kamon.instrumentation.http-client.noop"), TestComponent) + + def fakeRequest( + requestUrl: String, + requestPath: String, + requestMethod: String, + initialHeaders: Map[String, String] + ): HttpMessage.RequestBuilder[HttpMessage.Request] = new HttpMessage.RequestBuilder[HttpMessage.Request] { private var _headers = mutable.Map.empty[String, String] - initialHeaders.foreach { case (k, v) => _headers += (k -> v)} + initialHeaders.foreach { case (k, v) => _headers += (k -> v) } override def url: String = requestUrl - override def path: String = if(requestPath == "/fail-operation-name") sys.error("fail") else requestPath + override def path: String = if (requestPath == "/fail-operation-name") sys.error("fail") else requestPath override def method: String = requestMethod override def read(header: String): Option[String] = _headers.get(header) override def readAll(): Map[String, String] = _headers.toMap @@ -164,4 +190,4 @@ class HttpClientInstrumentationSpec extends AnyWordSpec with Matchers with Instr def parentSpan(): Span = Kamon.internalSpanBuilder("parent", "internal.code").start() -} \ No newline at end of file +} diff --git a/instrumentation/kamon-instrumentation-common/src/test/scala/kamon/instrumentation/http/HttpServerInstrumentationSpec.scala b/instrumentation/kamon-instrumentation-common/src/test/scala/kamon/instrumentation/http/HttpServerInstrumentationSpec.scala index 9f6ee5f32..cb69fc9c1 100644 --- a/instrumentation/kamon-instrumentation-common/src/test/scala/kamon/instrumentation/http/HttpServerInstrumentationSpec.scala +++ b/instrumentation/kamon-instrumentation-common/src/test/scala/kamon/instrumentation/http/HttpServerInstrumentationSpec.scala @@ -22,10 +22,15 @@ class HttpServerInstrumentationSpec extends AnyWordSpec with Matchers with Instr "the HTTP server instrumentation" when { "configured for context propagation" should { "read context entries and tags from the incoming request" in { - val handler = httpServer().createHandler(fakeRequest("http://localhost:8080/", "/", "GET", Map( - "context-tags" -> "tag=value;none=0011223344556677;", - "custom-trace-id" -> "0011223344556677" - ))) + val handler = httpServer().createHandler(fakeRequest( + "http://localhost:8080/", + "/", + "GET", + Map( + "context-tags" -> "tag=value;none=0011223344556677;", + "custom-trace-id" -> "0011223344556677" + ) + )) handler.context.tags.get(plain("tag")) shouldBe "value" handler.context.tags.get(plain("none")) shouldBe "0011223344556677" @@ -34,10 +39,15 @@ class HttpServerInstrumentationSpec extends AnyWordSpec with Matchers with Instr } "use the configured HTTP propagation channel" in { - val handler = httpServer().createHandler(fakeRequest("http://localhost:8080/", "/", "GET", Map( - "context-tags" -> "tag=value;none=0011223344556677;", - "custom-trace-id" -> "0011223344556677" - ))) + val handler = httpServer().createHandler(fakeRequest( + "http://localhost:8080/", + "/", + "GET", + Map( + "context-tags" -> "tag=value;none=0011223344556677;", + "custom-trace-id" -> "0011223344556677" + ) + )) handler.context.tags.get(plain("tag")) shouldBe "value" handler.context.tags.get(plain("none")) shouldBe "0011223344556677" @@ -83,7 +93,7 @@ class HttpServerInstrumentationSpec extends AnyWordSpec with Matchers with Instr httpServer().connectionClosed(Duration.ofSeconds(30), 15) val connectionUsageSnapshot = connectionUsage(8081).distribution() - connectionUsageSnapshot.buckets.map(_.value) should contain allOf( + connectionUsageSnapshot.buckets.map(_.value) should contain allOf ( 10, 15 ) @@ -98,9 +108,9 @@ class HttpServerInstrumentationSpec extends AnyWordSpec with Matchers with Instr httpServer().connectionClosed(Duration.ofSeconds(30), 15) val connectionLifetimeSnapshot = connectionLifetime(8081).distribution() - connectionLifetimeSnapshot.buckets.map(_.value) should contain allOf( + connectionLifetimeSnapshot.buckets.map(_.value) should contain allOf ( 19998441472L, // 20 seconds with 1% precision - 29930553344L // 30 seconds with 1% precision + 29930553344L // 30 seconds with 1% precision ) } @@ -133,7 +143,7 @@ class HttpServerInstrumentationSpec extends AnyWordSpec with Matchers with Instr httpServer().createHandler(fakeRequest("http://localhost:8080/", "/", "GET", Map.empty)).requestReceived(400) val requestSizeSnapshot = requestSize(8081).distribution() - requestSizeSnapshot.buckets.map(_.value) should contain allOf( + requestSizeSnapshot.buckets.map(_.value) should contain allOf ( 300, 400 ) @@ -146,7 +156,7 @@ class HttpServerInstrumentationSpec extends AnyWordSpec with Matchers with Instr httpServer().createHandler(fakeRequest("http://localhost:8080/", "/", "GET", Map.empty)).responseSent(400) val requestSizeSnapshot = responseSize(8081).distribution() - requestSizeSnapshot.buckets.map(_.value) should contain allOf( + requestSizeSnapshot.buckets.map(_.value) should contain allOf ( 300, 400 ) @@ -160,7 +170,6 @@ class HttpServerInstrumentationSpec extends AnyWordSpec with Matchers with Instr completedRequests(8081, 400).value() completedRequests(8081, 500).value() - val request = fakeRequest("http://localhost:8080/", "/", "GET", Map.empty) httpServer().createHandler(request).buildResponse(fakeResponse(200, mutable.Map.empty), Context.Empty) httpServer().createHandler(request).buildResponse(fakeResponse(302, mutable.Map.empty), Context.Empty) @@ -198,10 +207,15 @@ class HttpServerInstrumentationSpec extends AnyWordSpec with Matchers with Instr } "adopt a traceID when explicitly provided" in { - val handler = httpServer().createHandler(fakeRequest("http://localhost:8080/", "/", "GET", Map( - "context-tags" -> "tag=value;none=0011223344556677;", - "x-correlation-id" -> "0011223344556677" - ))) + val handler = httpServer().createHandler(fakeRequest( + "http://localhost:8080/", + "/", + "GET", + Map( + "context-tags" -> "tag=value;none=0011223344556677;", + "x-correlation-id" -> "0011223344556677" + ) + )) handler.span.trace.id.string shouldBe "0011223344556677" } @@ -222,18 +236,28 @@ class HttpServerInstrumentationSpec extends AnyWordSpec with Matchers with Instr } "receive tags from context when available" in { - val handler = httpServer().createHandler(fakeRequest("http://localhost:8080/", "/", "GET", Map( - "context-tags" -> "tag=value;none=0011223344556677;initiator.name=superservice;", - "custom-trace-id" -> "0011223344556677" - ))) + val handler = httpServer().createHandler(fakeRequest( + "http://localhost:8080/", + "/", + "GET", + Map( + "context-tags" -> "tag=value;none=0011223344556677;initiator.name=superservice;", + "custom-trace-id" -> "0011223344556677" + ) + )) handler.context.getTag(plain("initiator.name")) shouldBe "superservice" } "write trace identifiers on the responses" in { - val handler = httpServer().createHandler(fakeRequest("http://localhost:8080/", "/", "GET", Map( - "x-correlation-id" -> "0011223344556677" - ))) + val handler = httpServer().createHandler(fakeRequest( + "http://localhost:8080/", + "/", + "GET", + Map( + "x-correlation-id" -> "0011223344556677" + ) + )) val responseHeaders = mutable.Map.empty[String, String] handler.buildResponse(fakeResponse(200, responseHeaders), handler.context) @@ -243,7 +267,8 @@ class HttpServerInstrumentationSpec extends AnyWordSpec with Matchers with Instr } "honour user provided operation name mappings" in { - val handler = httpServer().createHandler(fakeRequest("http://localhost:8080/", "/events/123/rsvps", "GET", Map.empty)) + val handler = + httpServer().createHandler(fakeRequest("http://localhost:8080/", "/events/123/rsvps", "GET", Map.empty)) handler.buildResponse(fakeResponse(200, mutable.Map.empty), handler.context) val span = handler.span @@ -254,7 +279,8 @@ class HttpServerInstrumentationSpec extends AnyWordSpec with Matchers with Instr } "use the HTTP method as operation name when provided as operation name generator" in { - val handler = methodNamingHttpServer().createHandler(fakeRequest("http://localhost:8080/", "/", "PUT", Map.empty)) + val handler = + methodNamingHttpServer().createHandler(fakeRequest("http://localhost:8080/", "/", "PUT", Map.empty)) handler.buildResponse(fakeResponse(200, mutable.Map.empty), handler.context) val span = handler.span @@ -262,7 +288,8 @@ class HttpServerInstrumentationSpec extends AnyWordSpec with Matchers with Instr } "use the generated operation name when provided custom operation name generator is configured" in { - val handler = customNamingHttpServer().createHandler(fakeRequest("http://localhost:8080/", "/", "PUT", Map.empty)) + val handler = + customNamingHttpServer().createHandler(fakeRequest("http://localhost:8080/", "/", "PUT", Map.empty)) handler.buildResponse(fakeResponse(200, mutable.Map.empty), handler.context) val span = handler.span @@ -273,20 +300,30 @@ class HttpServerInstrumentationSpec extends AnyWordSpec with Matchers with Instr "all capabilities are disabled" should { "not read any context from the incoming requests" in { val httpServer = noopHttpServer() - val handler = httpServer.createHandler(fakeRequest("http://localhost:8080/", "/", "GET", Map( - "context-tags" -> "tag=value;none=0011223344556677;", - "custom-trace-id" -> "0011223344556677" - ))) + val handler = httpServer.createHandler(fakeRequest( + "http://localhost:8080/", + "/", + "GET", + Map( + "context-tags" -> "tag=value;none=0011223344556677;", + "custom-trace-id" -> "0011223344556677" + ) + )) handler.context shouldBe Context.Empty } "not create any span to represent the server request" in { val httpServer = noopHttpServer() - val handler = httpServer.createHandler(fakeRequest("http://localhost:8080/", "/", "GET", Map( - "context-tags" -> "tag=value;none=0011223344556677;", - "custom-trace-id" -> "0011223344556677" - ))) + val handler = httpServer.createHandler(fakeRequest( + "http://localhost:8080/", + "/", + "GET", + Map( + "context-tags" -> "tag=value;none=0011223344556677;", + "custom-trace-id" -> "0011223344556677" + ) + )) handler.span.isEmpty shouldBe true } @@ -306,10 +343,15 @@ class HttpServerInstrumentationSpec extends AnyWordSpec with Matchers with Instr completedRequests(8083, 500).value() shouldBe 0L } } - + "configured for custom response header generation" should { "provide additional headers in response" in { - val handler = customHttpServerResponseHeaderGenerator().createHandler(fakeRequest("http://localhost:8080/", "/", "PUT", Map.empty)) + val handler = customHttpServerResponseHeaderGenerator().createHandler(fakeRequest( + "http://localhost:8080/", + "/", + "PUT", + Map.empty + )) val responseHeaders = mutable.Map.empty[String, String] handler.buildResponse(fakeResponse(200, responseHeaders), handler.context) @@ -321,24 +363,50 @@ class HttpServerInstrumentationSpec extends AnyWordSpec with Matchers with Instr val TestComponent = "http.server" val TestInterface = "0.0.0.0" - def httpServer(): HttpServerInstrumentation = HttpServerInstrumentation.from(ConfigFactory.empty(), TestComponent, TestInterface, port = 8081) + def httpServer(): HttpServerInstrumentation = + HttpServerInstrumentation.from(ConfigFactory.empty(), TestComponent, TestInterface, port = 8081) def noSpanMetricsHttpServer(): HttpServerInstrumentation = HttpServerInstrumentation.from( - Kamon.config().getConfig("kamon.instrumentation.http-server.no-span-metrics"), TestComponent, TestInterface, port = 8082) + Kamon.config().getConfig("kamon.instrumentation.http-server.no-span-metrics"), + TestComponent, + TestInterface, + port = 8082 + ) def noopHttpServer(): HttpServerInstrumentation = HttpServerInstrumentation.from( - Kamon.config().getConfig("kamon.instrumentation.http-server.noop"), TestComponent, TestInterface, port = 8083) + Kamon.config().getConfig("kamon.instrumentation.http-server.noop"), + TestComponent, + TestInterface, + port = 8083 + ) def methodNamingHttpServer(): HttpServerInstrumentation = HttpServerInstrumentation.from( - Kamon.config().getConfig("kamon.instrumentation.http-server.with-method-operation-name-generator"), TestComponent, TestInterface, port = 8084) + Kamon.config().getConfig("kamon.instrumentation.http-server.with-method-operation-name-generator"), + TestComponent, + TestInterface, + port = 8084 + ) def customNamingHttpServer(): HttpServerInstrumentation = HttpServerInstrumentation.from( - Kamon.config().getConfig("kamon.instrumentation.http-server.with-custom-operation-name-generator"), TestComponent, TestInterface, port = 8084) + Kamon.config().getConfig("kamon.instrumentation.http-server.with-custom-operation-name-generator"), + TestComponent, + TestInterface, + port = 8084 + ) def customHttpServerResponseHeaderGenerator(): HttpServerInstrumentation = HttpServerInstrumentation.from( - Kamon.config().getConfig("kamon.instrumentation.http-server.with-custom-server-response-header-generator"), TestComponent, TestInterface, port = 8084) - - def fakeRequest(requestUrl: String, requestPath: String, requestMethod: String, headers: Map[String, String]): HttpMessage.Request = + Kamon.config().getConfig("kamon.instrumentation.http-server.with-custom-server-response-header-generator"), + TestComponent, + TestInterface, + port = 8084 + ) + + def fakeRequest( + requestUrl: String, + requestPath: String, + requestMethod: String, + headers: Map[String, String] + ): HttpMessage.Request = new HttpMessage.Request { override def url: String = requestUrl override def path: String = requestPath @@ -349,7 +417,10 @@ class HttpServerInstrumentationSpec extends AnyWordSpec with Matchers with Instr override def port: Int = 8081 } - def fakeResponse(responseStatusCode: Int, headers: mutable.Map[String, String]): HttpMessage.ResponseBuilder[HttpMessage.Response] = + def fakeResponse( + responseStatusCode: Int, + headers: mutable.Map[String, String] + ): HttpMessage.ResponseBuilder[HttpMessage.Response] = new HttpMessage.ResponseBuilder[HttpMessage.Response] { override def statusCode: Int = responseStatusCode override def write(header: String, value: String): Unit = headers.put(header, value) @@ -396,4 +467,4 @@ class DedicatedNameGenerator extends HttpOperationNameGenerator { class DedicatedResponseHeaderGenerator extends HttpServerResponseHeaderGenerator { override def headers(context: Context): Map[String, String] = Map("custom-header" -> "123-321") -} \ No newline at end of file +} diff --git a/instrumentation/kamon-jdbc/src/main/scala/kamon/instrumentation/jdbc/HikariInstrumentation.scala b/instrumentation/kamon-jdbc/src/main/scala/kamon/instrumentation/jdbc/HikariInstrumentation.scala index 584ddc3b6..363835b2a 100644 --- a/instrumentation/kamon-jdbc/src/main/scala/kamon/instrumentation/jdbc/HikariInstrumentation.scala +++ b/instrumentation/kamon-jdbc/src/main/scala/kamon/instrumentation/jdbc/HikariInstrumentation.scala @@ -67,7 +67,8 @@ trait HasConnectionPoolTelemetry { object HasConnectionPoolTelemetry { - class Mixin(var connectionPoolTelemetry: AtomicReference[ConnectionPoolTelemetry]) extends HasConnectionPoolTelemetry { + class Mixin(var connectionPoolTelemetry: AtomicReference[ConnectionPoolTelemetry]) + extends HasConnectionPoolTelemetry { override def setConnectionPoolTelemetry(cpTelemetry: AtomicReference[ConnectionPoolTelemetry]): Unit = this.connectionPoolTelemetry = cpTelemetry } @@ -78,7 +79,9 @@ object CheckFailFastAdvice { @Advice.OnMethodEnter @static def enter(@Advice.This hikariPool: Any): Unit = { - hikariPool.asInstanceOf[HasConnectionPoolTelemetry].setConnectionPoolTelemetry(new AtomicReference[ConnectionPoolTelemetry]()) + hikariPool.asInstanceOf[HasConnectionPoolTelemetry].setConnectionPoolTelemetry( + new AtomicReference[ConnectionPoolTelemetry]() + ) } } @@ -86,7 +89,10 @@ class HikariPoolConstructorAdvice object HikariPoolConstructorAdvice { @Advice.OnMethodExit - @static def exit(@Advice.This hikariPool: HasConnectionPoolTelemetry, @Advice.Argument(0) config: HikariConfig): Unit = { + @static def exit( + @Advice.This hikariPool: HasConnectionPoolTelemetry, + @Advice.Argument(0) config: HikariConfig + ): Unit = { val url = config.getJdbcUrl() val vendor = Try(url.split(':')(1)).getOrElse("unknown") @@ -118,7 +124,7 @@ object HikariPoolCreatePoolEntryMethodAdvice { @Advice.OnMethodExit @static def exit(@This hikariPool: HasConnectionPoolTelemetry, @Advice.Return poolEntry: Any): Unit = { - if(hikariPool != null && poolEntry != null) { + if (hikariPool != null && poolEntry != null) { poolEntry.asInstanceOf[HasConnectionPoolTelemetry].setConnectionPoolTelemetry(hikariPool.connectionPoolTelemetry) val poolTelemetry = hikariPool.connectionPoolTelemetry.get @@ -134,7 +140,9 @@ object HikariPoolCloseConnectionMethodAdvice { @Advice.OnMethodExit @static def exit(@This hikariPool: Any): Unit = { - hikariPool.asInstanceOf[HasConnectionPoolTelemetry].connectionPoolTelemetry.get.instruments.openConnections.decrement() + hikariPool.asInstanceOf[ + HasConnectionPoolTelemetry + ].connectionPoolTelemetry.get.instruments.openConnections.decrement() } } @@ -143,7 +151,9 @@ object HikariPoolCreateTimeoutExceptionMethodAdvice { @Advice.OnMethodExit @static def exit(@This hikariPool: Any): Unit = - hikariPool.asInstanceOf[HasConnectionPoolTelemetry].connectionPoolTelemetry.get.instruments.borrowTimeouts.increment() + hikariPool.asInstanceOf[ + HasConnectionPoolTelemetry + ].connectionPoolTelemetry.get.instruments.borrowTimeouts.increment() } class ProxyConnectionCloseMethodAdvice @@ -151,7 +161,9 @@ object ProxyConnectionCloseMethodAdvice { @Advice.OnMethodExit @static def exit(@This proxyConnection: Any): Unit = { - proxyConnection.asInstanceOf[HasConnectionPoolTelemetry].connectionPoolTelemetry.get.instruments.borrowedConnections.decrement() + proxyConnection.asInstanceOf[ + HasConnectionPoolTelemetry + ].connectionPoolTelemetry.get.instruments.borrowedConnections.decrement() } } @@ -179,15 +191,19 @@ object HikariPoolGetConnectionAdvice { } @Advice.OnMethodExit(onThrowable = classOf[Exception]) - @static def executeEnd(@Advice.Enter startTime: Long, @Advice.Return connection: Connection, @Advice.This pool: HasConnectionPoolTelemetry, - @Advice.Thrown throwable: java.lang.Throwable): Unit = { + @static def executeEnd( + @Advice.Enter startTime: Long, + @Advice.Return connection: Connection, + @Advice.This pool: HasConnectionPoolTelemetry, + @Advice.Thrown throwable: java.lang.Throwable + ): Unit = { val borrowTime = System.nanoTime() - startTime val poolMetrics = pool.connectionPoolTelemetry.get poolMetrics.instruments.borrowTime.record(borrowTime) - if(throwable == null && connection != null) { + if (throwable == null && connection != null) { poolMetrics.instruments.borrowedConnections.increment() connection .asInstanceOf[HasConnectionPoolTelemetry] @@ -202,7 +218,9 @@ object PoolBaseNewConnectionAdvice { @Advice.OnMethodEnter @static def enter(@Advice.This pool: Any, @Advice.Argument(0) connection: Any): Scope = { - connection.asInstanceOf[HasConnectionPoolTelemetry].setConnectionPoolTelemetry(pool.asInstanceOf[HasConnectionPoolTelemetry].connectionPoolTelemetry) + connection.asInstanceOf[HasConnectionPoolTelemetry].setConnectionPoolTelemetry( + pool.asInstanceOf[HasConnectionPoolTelemetry].connectionPoolTelemetry + ) Kamon.storeContext(Kamon.currentContext().withEntry(PreStart.Key, PreStart.updateOperationName("init"))) } @@ -218,8 +236,10 @@ object CreateProxyConnectionAdvice { @Advice.OnMethodExit @static def exit(@Advice.This poolEntry: Any): Unit = { val realConnection = PoolEntryProtectedAccess.underlyingConnection(poolEntry) - if(realConnection != null) { - realConnection.asInstanceOf[HasConnectionPoolTelemetry].setConnectionPoolTelemetry(poolEntry.asInstanceOf[HasConnectionPoolTelemetry].connectionPoolTelemetry) + if (realConnection != null) { + realConnection.asInstanceOf[HasConnectionPoolTelemetry].setConnectionPoolTelemetry( + poolEntry.asInstanceOf[HasConnectionPoolTelemetry].connectionPoolTelemetry + ) } } } diff --git a/instrumentation/kamon-jdbc/src/main/scala/kamon/instrumentation/jdbc/JdbcInstrumentation.scala b/instrumentation/kamon-jdbc/src/main/scala/kamon/instrumentation/jdbc/JdbcInstrumentation.scala index 6ee0280a6..5dcadbb9a 100644 --- a/instrumentation/kamon-jdbc/src/main/scala/kamon/instrumentation/jdbc/JdbcInstrumentation.scala +++ b/instrumentation/kamon-jdbc/src/main/scala/kamon/instrumentation/jdbc/JdbcInstrumentation.scala @@ -31,15 +31,18 @@ object JdbcInstrumentation extends LoggingSupport { Kamon.onReconfigure(newConfig => _settings = readSettings(newConfig)) private[jdbc] def onStatementFinish(statement: String, elapsedTimeNanos: Long): Unit = { - if(elapsedTimeNanos >= _settings.slowStatementThresholdNanos) - _settings.slowStatementProcessors.foreach(_.process(statement, elapsedTimeNanos, _settings.slowStatementThresholdNanos)) + if (elapsedTimeNanos >= _settings.slowStatementThresholdNanos) + _settings.slowStatementProcessors.foreach(_.process( + statement, + elapsedTimeNanos, + _settings.slowStatementThresholdNanos + )) } private[jdbc] def onStatementFailure(statement: String, error: Throwable): Unit = { _settings.failedStatementProcessors.foreach(_.process(statement, error)) } - /** * Callback for notifications of statements taking longer than "kamon.instrumentation.jdbc.statements.slow.threshold" * to execute. @@ -55,7 +58,6 @@ object JdbcInstrumentation extends LoggingSupport { def process(sql: String, ex: Throwable): Unit } - object LoggingProcessors { final class WarnOnSlowStatement extends SlowStatementProcessor with LoggingSupport { @@ -63,7 +65,9 @@ object JdbcInstrumentation extends LoggingSupport { val threshold = Duration.create(slowThresholdNanos, TimeUnit.NANOSECONDS) val statementDuration = Duration.create(elapsedTimeNanos, TimeUnit.NANOSECONDS) - logWarn(s"Query execution exceeded the [${threshold}] threshold and lasted [${statementDuration}]. The query was: [$statement]") + logWarn( + s"Query execution exceeded the [${threshold}] threshold and lasted [${statementDuration}]. The query was: [$statement]" + ) } } @@ -74,8 +78,7 @@ object JdbcInstrumentation extends LoggingSupport { } } - - private case class Settings ( + private case class Settings( slowStatementThresholdNanos: Long, slowStatementProcessors: List[SlowStatementProcessor], failedStatementProcessors: List[FailedStatementProcessor] @@ -91,7 +94,7 @@ object JdbcInstrumentation extends LoggingSupport { .map(fqcn => ClassLoading.createInstance[FailedStatementProcessor](fqcn)) .toList - Settings ( + Settings( slowStatementThresholdNanos = jdbcConfig.getDuration("statements.slow.threshold").toNanos(), slowStatementProcessors, failedStatementProcessors diff --git a/instrumentation/kamon-jdbc/src/main/scala/kamon/instrumentation/jdbc/JdbcMetrics.scala b/instrumentation/kamon-jdbc/src/main/scala/kamon/instrumentation/jdbc/JdbcMetrics.scala index d8ca568c9..7bd270d52 100644 --- a/instrumentation/kamon-jdbc/src/main/scala/kamon/instrumentation/jdbc/JdbcMetrics.scala +++ b/instrumentation/kamon-jdbc/src/main/scala/kamon/instrumentation/jdbc/JdbcMetrics.scala @@ -22,7 +22,7 @@ import kamon.tag.TagSet object JdbcMetrics { - val OpenConnections = Kamon.rangeSampler ( + val OpenConnections = Kamon.rangeSampler( name = "jdbc.pool.connections.open", description = "Tracks the number of open connections in a pool" ) @@ -32,7 +32,7 @@ object JdbcMetrics { description = "Tracks the number of borrowed connections in a pool" ) - val BorrowTime = Kamon.timer ( + val BorrowTime = Kamon.timer( name = "jdbc.pool.borrow-time", description = "Tracks the time it takes for the connection pool to lease a connection" ) diff --git a/instrumentation/kamon-jdbc/src/main/scala/kamon/instrumentation/jdbc/StatementInstrumentation.scala b/instrumentation/kamon-jdbc/src/main/scala/kamon/instrumentation/jdbc/StatementInstrumentation.scala index a82bb2f19..22bf5763a 100644 --- a/instrumentation/kamon-jdbc/src/main/scala/kamon/instrumentation/jdbc/StatementInstrumentation.scala +++ b/instrumentation/kamon-jdbc/src/main/scala/kamon/instrumentation/jdbc/StatementInstrumentation.scala @@ -68,7 +68,6 @@ class StatementInstrumentation extends InstrumentationBuilder { .advise(method("executeQuery"), classOf[PreparedStatementExecuteQueryMethodAdvisor]) .advise(method("executeUpdate"), classOf[PreparedStatementExecuteUpdateMethodAdvisor]) - /** * We are specifically targeting some of the SQLite Driver classes because due to the way in which inheritance is * handled within the Driver these advices were not applied at all. All other drivers tested so far should work just @@ -128,11 +127,15 @@ class DriverConnectAdvice object DriverConnectAdvice { @Advice.OnMethodExit - @static def exit(@Advice.Argument(0) url: String, @Advice.Argument(1) properties: Properties, @Advice.Return connection: Any): Unit = { + @static def exit( + @Advice.Argument(0) url: String, + @Advice.Argument(1) properties: Properties, + @Advice.Return connection: Any + ): Unit = { // The connection could be null if there is more than one registered driver and the DriverManager is looping // through them to figure out which one accepts the URL. - if(connection != null) { + if (connection != null) { connection.asInstanceOf[HasDatabaseTags].setDatabaseTags(createDatabaseTags(url, properties)) } } @@ -155,7 +158,9 @@ object CreateStatementAdvice { @Advice.OnMethodExit @static def exit(@Advice.This connection: Any, @Advice.Return statement: Any): Unit = { statement.asInstanceOf[HasDatabaseTags].setDatabaseTags(connection.asInstanceOf[HasDatabaseTags].databaseTags()) - statement.asInstanceOf[HasConnectionPoolTelemetry].setConnectionPoolTelemetry(connection.asInstanceOf[HasConnectionPoolTelemetry].connectionPoolTelemetry) + statement.asInstanceOf[HasConnectionPoolTelemetry].setConnectionPoolTelemetry( + connection.asInstanceOf[HasConnectionPoolTelemetry].connectionPoolTelemetry + ) } } @@ -163,9 +168,15 @@ class CreatePreparedStatementAdvice object CreatePreparedStatementAdvice { @Advice.OnMethodExit - @static def exit(@Advice.This connection: Any, @Advice.Argument(0) sql: String, @Advice.Return statement: Any): Unit = { + @static def exit( + @Advice.This connection: Any, + @Advice.Argument(0) sql: String, + @Advice.Return statement: Any + ): Unit = { statement.asInstanceOf[HasDatabaseTags].setDatabaseTags(connection.asInstanceOf[HasDatabaseTags].databaseTags()) - statement.asInstanceOf[HasConnectionPoolTelemetry].setConnectionPoolTelemetry(statement.asInstanceOf[HasConnectionPoolTelemetry].connectionPoolTelemetry) + statement.asInstanceOf[HasConnectionPoolTelemetry].setConnectionPoolTelemetry( + statement.asInstanceOf[HasConnectionPoolTelemetry].connectionPoolTelemetry + ) statement.asInstanceOf[HasStatementSQL].setStatementSQL(sql) } } @@ -183,7 +194,6 @@ object ConnectionIsValidAdvice { scope.close() } - class PgConnectionIsAliveAdvice object PgConnectionIsAliveAdvice { @@ -195,13 +205,13 @@ object PgConnectionIsAliveAdvice { @Advice.OnMethodEnter @static def enter(@Advice.This connection: Any): Unit = { - if(connection != null) { + if (connection != null) { val statement = connection.asInstanceOf[PgConnectionPrivateAccess].getCheckConnectionStatement() - if(statement != null) { + if (statement != null) { val connectionPoolTelemetry = connection.asInstanceOf[HasConnectionPoolTelemetry].connectionPoolTelemetry statement.asInstanceOf[HasConnectionPoolTelemetry].setConnectionPoolTelemetry(connectionPoolTelemetry) } } } -} \ No newline at end of file +} diff --git a/instrumentation/kamon-jdbc/src/main/scala/kamon/instrumentation/jdbc/StatementMonitor.scala b/instrumentation/kamon-jdbc/src/main/scala/kamon/instrumentation/jdbc/StatementMonitor.scala index 1b62d1325..ea4d854fe 100644 --- a/instrumentation/kamon-jdbc/src/main/scala/kamon/instrumentation/jdbc/StatementMonitor.scala +++ b/instrumentation/kamon-jdbc/src/main/scala/kamon/instrumentation/jdbc/StatementMonitor.scala @@ -29,7 +29,6 @@ import java.sql.PreparedStatement import java.time.Instant import java.time.temporal.ChronoUnit - object StatementMonitor extends LoggingSupport { object StatementTypes { @@ -65,7 +64,7 @@ object StatementMonitor extends LoggingSupport { case unrecognizedValue => logger.warn(s"Unrecognized value [${unrecognizedValue}] for the [add-db-statement-as-span-tag] setting. " + - s"Falling back to [always]") + s"Falling back to [always]") } } @@ -76,7 +75,8 @@ object StatementMonitor extends LoggingSupport { // It could happen that there is no Pool Telemetry on the Pool when fail-fast is enabled and a connection is // created while the Pool's constructor is still executing. val (inFlightRangeSampler: RangeSampler, databaseTags: DatabaseTags) = statement match { - case cpt: HasConnectionPoolTelemetry if cpt.connectionPoolTelemetry != null && cpt.connectionPoolTelemetry.get() != null => + case cpt: HasConnectionPoolTelemetry + if cpt.connectionPoolTelemetry != null && cpt.connectionPoolTelemetry.get() != null => val poolTelemetry = cpt.connectionPoolTelemetry.get() (poolTelemetry.instruments.inFlightStatements, poolTelemetry.databaseTags) @@ -106,11 +106,15 @@ object StatementMonitor extends LoggingSupport { val clientSpan = Kamon.clientSpanBuilder(spanName, "jdbc") - if(addStatementSQL || (statement.isInstanceOf[PreparedStatement] && addPreparedStatementSQL)) + if (addStatementSQL || (statement.isInstanceOf[PreparedStatement] && addPreparedStatementSQL)) clientSpan.tag("db.statement", sql) - databaseTags.spanTags.iterator().foreach(t => clientSpan.tag(t.key, databaseTags.spanTags.get(Lookups.coerce(t.key)))) - databaseTags.metricTags.iterator().foreach(t => clientSpan.tagMetrics(t.key, databaseTags.metricTags.get(Lookups.coerce(t.key)))) + databaseTags.spanTags.iterator().foreach(t => + clientSpan.tag(t.key, databaseTags.spanTags.get(Lookups.coerce(t.key))) + ) + databaseTags.metricTags.iterator().foreach(t => + clientSpan.tagMetrics(t.key, databaseTags.metricTags.get(Lookups.coerce(t.key))) + ) inFlightRangeSampler.increment() Some(Invocation(statement, clientSpan.start(startTimestamp), sql, startTimestamp, inFlightRangeSampler)) diff --git a/instrumentation/kamon-jdbc/src/main/scala/kamon/instrumentation/jdbc/advisor/StatementInstrumentationAdvisors.scala b/instrumentation/kamon-jdbc/src/main/scala/kamon/instrumentation/jdbc/advisor/StatementInstrumentationAdvisors.scala index 5096ea334..627f524c6 100644 --- a/instrumentation/kamon-jdbc/src/main/scala/kamon/instrumentation/jdbc/advisor/StatementInstrumentationAdvisors.scala +++ b/instrumentation/kamon-jdbc/src/main/scala/kamon/instrumentation/jdbc/advisor/StatementInstrumentationAdvisors.scala @@ -56,12 +56,11 @@ object PreparedStatementExecuteMethodAdvisor { } } - /** * Advisor for java.sql.Statement::executeQuery */ class StatementExecuteQueryMethodAdvisor -object StatementExecuteQueryMethodAdvisor { +object StatementExecuteQueryMethodAdvisor { @Advice.OnMethodEnter(suppress = classOf[Throwable]) @static def executeStart(@Advice.This statement: Any, @Advice.Argument(0) sql: String): Option[Invocation] = { StatementMonitor.start(statement, sql, StatementTypes.Query) @@ -93,7 +92,7 @@ object PreparedStatementExecuteQueryMethodAdvisor { * Advisor for java.sql.Statement::executeUpdate */ class StatementExecuteUpdateMethodAdvisor -object StatementExecuteUpdateMethodAdvisor { +object StatementExecuteUpdateMethodAdvisor { @Advice.OnMethodEnter(suppress = classOf[Throwable]) @static def executeStart(@Advice.This statement: Any, @Advice.Argument(0) sql: String): Option[Invocation] = { StatementMonitor.start(statement, sql, StatementTypes.Update) @@ -126,13 +125,13 @@ object PreparedStatementExecuteUpdateMethodAdvisor { * Advisor for java.sql.Statement+::executeLargeBatch */ class StatementExecuteBatchMethodAdvisor -object StatementExecuteBatchMethodAdvisor { +object StatementExecuteBatchMethodAdvisor { // inline @Advice.OnMethodEnter(suppress = classOf[Throwable]) @static def executeStart(@Advice.This statement: Any): Option[Invocation] = { val statementSQL = statement match { case hSQL: HasStatementSQL => hSQL.capturedStatementSQL() - case _ => statement.toString + case _ => statement.toString } StatementMonitor.start(statement, statementSQL, StatementTypes.Batch) diff --git a/instrumentation/kamon-jdbc/src/main/scala/kamon/instrumentation/jdbc/internal/PoolEntryProtectedAccess.scala b/instrumentation/kamon-jdbc/src/main/scala/kamon/instrumentation/jdbc/internal/PoolEntryProtectedAccess.scala index 14191e654..5808a0a16 100644 --- a/instrumentation/kamon-jdbc/src/main/scala/kamon/instrumentation/jdbc/internal/PoolEntryProtectedAccess.scala +++ b/instrumentation/kamon-jdbc/src/main/scala/kamon/instrumentation/jdbc/internal/PoolEntryProtectedAccess.scala @@ -25,6 +25,6 @@ object PoolEntryProtectedAccess { */ def underlyingConnection(poolEntry: Any): Connection = poolEntry match { case pe: PoolEntry => pe.connection - case _ => null + case _ => null } } diff --git a/instrumentation/kamon-jdbc/src/main/scala/kamon/instrumentation/jdbc/utils/SqlVisitor.scala b/instrumentation/kamon-jdbc/src/main/scala/kamon/instrumentation/jdbc/utils/SqlVisitor.scala index 7d34f0310..bca269a56 100644 --- a/instrumentation/kamon-jdbc/src/main/scala/kamon/instrumentation/jdbc/utils/SqlVisitor.scala +++ b/instrumentation/kamon-jdbc/src/main/scala/kamon/instrumentation/jdbc/utils/SqlVisitor.scala @@ -1,7 +1,23 @@ package kamon.instrumentation.jdbc.utils import net.sf.jsqlparser.schema.Table -import net.sf.jsqlparser.statement.{Block, Commit, CreateFunctionalStatement, DeclareStatement, DescribeStatement, ExplainStatement, ResetStatement, RollbackStatement, SavepointStatement, SetStatement, ShowColumnsStatement, ShowStatement, StatementVisitor, Statements, UseStatement} +import net.sf.jsqlparser.statement.{ + Block, + Commit, + CreateFunctionalStatement, + DeclareStatement, + DescribeStatement, + ExplainStatement, + ResetStatement, + RollbackStatement, + SavepointStatement, + SetStatement, + ShowColumnsStatement, + ShowStatement, + StatementVisitor, + Statements, + UseStatement +} import net.sf.jsqlparser.statement.alter.{Alter, AlterSession} import net.sf.jsqlparser.statement.alter.sequence.AlterSequence import net.sf.jsqlparser.statement.comment.Comment @@ -18,14 +34,27 @@ import net.sf.jsqlparser.statement.grant.Grant import net.sf.jsqlparser.statement.insert.Insert import net.sf.jsqlparser.statement.merge.Merge import net.sf.jsqlparser.statement.replace.Replace -import net.sf.jsqlparser.statement.select.{FromItemVisitor, LateralSubSelect, ParenthesisFromItem, PlainSelect, Select, SelectVisitor, SetOperationList, SubJoin, SubSelect, TableFunction, ValuesList, WithItem} +import net.sf.jsqlparser.statement.select.{ + FromItemVisitor, + LateralSubSelect, + ParenthesisFromItem, + PlainSelect, + Select, + SelectVisitor, + SetOperationList, + SubJoin, + SubSelect, + TableFunction, + ValuesList, + WithItem +} import net.sf.jsqlparser.statement.show.ShowTablesStatement import net.sf.jsqlparser.statement.truncate.Truncate import net.sf.jsqlparser.statement.update.Update import net.sf.jsqlparser.statement.upsert.Upsert import net.sf.jsqlparser.statement.values.ValuesStatement -class SqlVisitor(var operation: String) extends StatementVisitor with FromItemVisitor with SelectVisitor { +class SqlVisitor(var operation: String) extends StatementVisitor with FromItemVisitor with SelectVisitor { override def visit(comment: Comment): Unit = {} override def visit(commit: Commit): Unit = operation = "commit" @@ -76,7 +105,8 @@ class SqlVisitor(var operation: String) extends StatementVisitor with FromItemVi override def visit(subjoin: SubJoin): Unit = operation = s"select ${subjoin.getAlias.toString}" - override def visit(lateralSubSelect: LateralSubSelect): Unit = operation = s"select ${lateralSubSelect.getAlias.toString}" + override def visit(lateralSubSelect: LateralSubSelect): Unit = + operation = s"select ${lateralSubSelect.getAlias.toString}" override def visit(valuesList: ValuesList): Unit = operation = s"select ${valuesList.getAlias}" @@ -106,9 +136,11 @@ class SqlVisitor(var operation: String) extends StatementVisitor with FromItemVi override def visit(grant: Grant): Unit = operation = "grant" - override def visit(createSequence: CreateSequence): Unit = operation = s"create_sequnce ${createSequence.sequence.getName}" + override def visit(createSequence: CreateSequence): Unit = + operation = s"create_sequnce ${createSequence.sequence.getName}" - override def visit(alterSequence: AlterSequence): Unit = operation = s"alter_sequence ${alterSequence.sequence.getName}" + override def visit(alterSequence: AlterSequence): Unit = + operation = s"alter_sequence ${alterSequence.sequence.getName}" override def visit(createFunctionalStatement: CreateFunctionalStatement): Unit = {} diff --git a/instrumentation/kamon-jdbc/src/test/scala/kamon/instrumentation/jdbc/HikariInstrumentationSpec.scala b/instrumentation/kamon-jdbc/src/test/scala/kamon/instrumentation/jdbc/HikariInstrumentationSpec.scala index b60dfd603..33036b7c0 100644 --- a/instrumentation/kamon-jdbc/src/test/scala/kamon/instrumentation/jdbc/HikariInstrumentationSpec.scala +++ b/instrumentation/kamon-jdbc/src/test/scala/kamon/instrumentation/jdbc/HikariInstrumentationSpec.scala @@ -32,18 +32,19 @@ import org.scalatest.{BeforeAndAfterEach, OptionValues} import scala.concurrent.{ExecutionContext, ExecutionContextExecutor} class HikariInstrumentationSpec extends AnyWordSpec - with Matchers - with Eventually - with SpanSugar - with MetricInspection.Syntax - with InstrumentInspection.Syntax - with TestSpanReporter - with BeforeAndAfterEach - with InitAndStopKamonAfterAll - with OptionValues { + with Matchers + with Eventually + with SpanSugar + with MetricInspection.Syntax + with InstrumentInspection.Syntax + with TestSpanReporter + with BeforeAndAfterEach + with InitAndStopKamonAfterAll + with OptionValues { import HikariInstrumentationSpec.{createH2Pool, createSQLitePool} - implicit val parallelQueriesContext: ExecutionContextExecutor = ExecutionContext.fromExecutor(Executors.newFixedThreadPool(16)) + implicit val parallelQueriesContext: ExecutionContextExecutor = + ExecutionContext.fromExecutor(Executors.newFixedThreadPool(16)) override def beforeEach() = testSpanReporter().clear() @@ -58,7 +59,7 @@ class HikariInstrumentationSpec extends AnyWordSpec val pool1 = createH2Pool("example-1") val pool2 = createH2Pool("example-2") - JdbcMetrics.OpenConnections.tagValues("jdbc.pool.name") should contain allOf( + JdbcMetrics.OpenConnections.tagValues("jdbc.pool.name") should contain allOf ( "example-1", "example-2" ) @@ -87,7 +88,7 @@ class HikariInstrumentationSpec extends AnyWordSpec connections.foreach(_.close()) - eventually(timeout(20 seconds), interval(1 second)) { + eventually(timeout(20 seconds), interval(1 second)) { JdbcMetrics.OpenConnections.withTags(tags).distribution(true).max shouldBe (0) } @@ -106,13 +107,13 @@ class HikariInstrumentationSpec extends AnyWordSpec .add("db.vendor", "h2") .build() - eventually(timeout(30 seconds), interval(1 second)) { + eventually(timeout(30 seconds), interval(1 second)) { JdbcMetrics.BorrowedConnections.withTags(tags).distribution().max shouldBe (10) } connections.drop(5).foreach(_.close()) - eventually(timeout(30 seconds), interval(1 second)) { + eventually(timeout(30 seconds), interval(1 second)) { JdbcMetrics.BorrowedConnections.withTags(tags).distribution().max shouldBe (5) } @@ -120,7 +121,6 @@ class HikariInstrumentationSpec extends AnyWordSpec pool.close() } - "track the time it takes to borrow a connection" in { val pool = createH2Pool("track-borrow-time", 5) val connections = (1 to 5).map { _ => @@ -164,8 +164,8 @@ class HikariInstrumentationSpec extends AnyWordSpec .add("db.vendor", "h2") .build() - val borrowTimeouts = JdbcMetrics.BorrowTimeouts.withTags(tags).value() - borrowTimeouts shouldBe 1 + val borrowTimeouts = JdbcMetrics.BorrowTimeouts.withTags(tags).value() + borrowTimeouts shouldBe 1 connections.foreach(_.close) pool.close() @@ -196,7 +196,6 @@ class HikariInstrumentationSpec extends AnyWordSpec connection.isValid(10) connection.isValid(10) - eventually(timeout(5 seconds)) { val span = testSpanReporter().nextSpan().value span.operationName shouldBe "isValid" @@ -227,7 +226,8 @@ object HikariInstrumentationSpec { .prepareStatement( """|CREATE TABLE Address (Nr INTEGER, Name VARCHAR(128)); |CREATE ALIAS SLEEP FOR "java.lang.Thread.sleep(long)"; - """.stripMargin) + """.stripMargin + ) .executeUpdate() setupConnection.close() diff --git a/instrumentation/kamon-jdbc/src/test/scala/kamon/instrumentation/jdbc/SlickInstrumentationSpec.scala b/instrumentation/kamon-jdbc/src/test/scala/kamon/instrumentation/jdbc/SlickInstrumentationSpec.scala index 836e1d4b3..0b8f522c3 100644 --- a/instrumentation/kamon-jdbc/src/test/scala/kamon/instrumentation/jdbc/SlickInstrumentationSpec.scala +++ b/instrumentation/kamon-jdbc/src/test/scala/kamon/instrumentation/jdbc/SlickInstrumentationSpec.scala @@ -38,7 +38,7 @@ class SlickInstrumentationSpec extends AnyWordSpec with Matchers with Eventually "the Slick instrumentation" should { "propagate the current Context to the AsyncExecutor on Slick" in { applyConfig("kamon.instrumentation.jdbc.add-db-statement-as-span-tag=always") - + val db = setup(Database.forConfig("slick-h2")) val parent = Kamon.spanBuilder("parent").start() @@ -95,4 +95,3 @@ class SlickInstrumentationSpec extends AnyWordSpec with Matchers with Eventually } } - diff --git a/instrumentation/kamon-jdbc/src/test/scala/kamon/instrumentation/jdbc/StatementInstrumentationSpec.scala b/instrumentation/kamon-jdbc/src/test/scala/kamon/instrumentation/jdbc/StatementInstrumentationSpec.scala index e42604917..7a4b63d8f 100644 --- a/instrumentation/kamon-jdbc/src/test/scala/kamon/instrumentation/jdbc/StatementInstrumentationSpec.scala +++ b/instrumentation/kamon-jdbc/src/test/scala/kamon/instrumentation/jdbc/StatementInstrumentationSpec.scala @@ -36,19 +36,19 @@ import scala.concurrent.{ExecutionContext, ExecutionContextExecutor, Future} import scala.util.{Failure, Success, Try} class StatementInstrumentationSpec extends AnyWordSpec - with Matchers - with Eventually - with SpanSugar - with BeforeAndAfterEach - with MetricInspection.Syntax - with InstrumentInspection.Syntax - with Reconfigure - with OptionValues - with InitAndStopKamonAfterAll - with TestSpanReporter { - - implicit val parallelQueriesExecutor: ExecutionContextExecutor = ExecutionContext.fromExecutor(Executors.newFixedThreadPool(10)) - + with Matchers + with Eventually + with SpanSugar + with BeforeAndAfterEach + with MetricInspection.Syntax + with InstrumentInspection.Syntax + with Reconfigure + with OptionValues + with InitAndStopKamonAfterAll + with TestSpanReporter { + + implicit val parallelQueriesExecutor: ExecutionContextExecutor = + ExecutionContext.fromExecutor(Executors.newFixedThreadPool(10)) override protected def beforeAll(): Unit = { super.beforeAll() @@ -71,7 +71,6 @@ class StatementInstrumentationSpec extends AnyWordSpec DriverSuite.HikariH2 ).filter(canRunInCurrentEnvironment) - "the StatementInstrumentation" when { drivers.foreach { driver => driver.init() @@ -100,7 +99,6 @@ class StatementInstrumentationSpec extends AnyWordSpec statement.execute(select) validateNextRow(statement.getResultSet, valueNr = 2, valueName = "foo") - eventually(timeout(scaled(5 seconds)), interval(200 millis)) { val span = commonSpanValidations(testSpanReporter(), driver) validateQuery(span, "select Address", select) @@ -229,7 +227,6 @@ class StatementInstrumentationSpec extends AnyWordSpec span.tags.get(option("db.statement")) shouldBe empty } - val ps = connection.prepareStatement("INSERT INTO Address VALUES(?, ?)") ps.setInt(1, 1) ps.setString(2, "test") @@ -253,7 +250,6 @@ class StatementInstrumentationSpec extends AnyWordSpec span.tags.get(option("db.statement")) shouldBe empty } - val ps = connection.prepareStatement("INSERT INTO Address VALUES(?, ?)") ps.setInt(1, 1) ps.setString(2, "test") @@ -275,7 +271,7 @@ class StatementInstrumentationSpec extends AnyWordSpec driver.sleep(connection, Duration.ofMillis(1500)) connection }.onComplete { - case Success(conn) => conn.close() + case Success(conn) => conn.close() case Failure(error) => println(s"An error has occured ${error.getMessage}") } } @@ -299,7 +295,10 @@ class StatementInstrumentationSpec extends AnyWordSpec } } - private def commonSpanValidations(testSpanReporter: BufferingSpanReporter, driver: DriverSuite with DriverSuite.AddressTableSetup) = { + private def commonSpanValidations( + testSpanReporter: BufferingSpanReporter, + driver: DriverSuite with DriverSuite.AddressTableSetup + ) = { val span = testSpanReporter.nextSpan().value span.metricTags.get(plain("db.vendor")) shouldBe driver.vendor span.metricTags.get(plain("component")) shouldBe "jdbc" @@ -319,7 +318,12 @@ class StatementInstrumentationSpec extends AnyWordSpec span } - private def validateNextRow(resultSet: ResultSet, valueNr: Int, valueName: String, shouldBeMore: Boolean = false): Unit = { + private def validateNextRow( + resultSet: ResultSet, + valueNr: Int, + valueName: String, + shouldBeMore: Boolean = false + ): Unit = { resultSet.next() shouldBe true resultSet.getInt("Nr") shouldBe valueNr resultSet.getString("Name") shouldBe valueName @@ -327,6 +331,7 @@ class StatementInstrumentationSpec extends AnyWordSpec } trait DriverSuite { + /** * Name of the driver being tested. */ @@ -362,7 +367,6 @@ class StatementInstrumentationSpec extends AnyWordSpec */ def sleep(connection: Connection, duration: Duration): Unit - /** * Closes created connections and pools */ @@ -377,7 +381,6 @@ class StatementInstrumentationSpec extends AnyWordSpec val url = "jdbc:h2:mem:jdbc-spec;MULTI_THREADED=1" val supportSleeping = true - override def init(): Unit = { val connection = connect() initializeAddressTable(connection) diff --git a/instrumentation/kamon-kafka/src/main/scala/kamon/instrumentation/kafka/client/ConsumerInstrumentation.scala b/instrumentation/kamon-kafka/src/main/scala/kamon/instrumentation/kafka/client/ConsumerInstrumentation.scala index d27331b5b..4aa497018 100644 --- a/instrumentation/kamon-kafka/src/main/scala/kamon/instrumentation/kafka/client/ConsumerInstrumentation.scala +++ b/instrumentation/kamon-kafka/src/main/scala/kamon/instrumentation/kafka/client/ConsumerInstrumentation.scala @@ -24,6 +24,7 @@ import kamon.instrumentation.kafka.client.advisor.PollMethodAdvisor import kanela.agent.api.instrumentation.InstrumentationBuilder class ConsumerInstrumentation extends InstrumentationBuilder { + /** * Instruments org.apache.kafka.clients.consumer.KafkaConsumer::poll(Long) * Kafka version < 2.3 @@ -73,4 +74,3 @@ object ConsumedRecordData { } } } - diff --git a/instrumentation/kamon-kafka/src/main/scala/kamon/instrumentation/kafka/client/ContextSerializationHelper.scala b/instrumentation/kamon-kafka/src/main/scala/kamon/instrumentation/kafka/client/ContextSerializationHelper.scala index 7be5a5f0d..699befb18 100644 --- a/instrumentation/kamon-kafka/src/main/scala/kamon/instrumentation/kafka/client/ContextSerializationHelper.scala +++ b/instrumentation/kamon-kafka/src/main/scala/kamon/instrumentation/kafka/client/ContextSerializationHelper.scala @@ -29,7 +29,7 @@ import kamon.context.{BinaryPropagation, Context} */ object ContextSerializationHelper { - def toByteArray(ctx: Context): Array[Byte] = { + def toByteArray(ctx: Context): Array[Byte] = { val out = new ByteArrayOutputStream(); Kamon.defaultBinaryPropagation().write(ctx, BinaryPropagation.ByteStreamWriter.of(out)) out.toByteArray diff --git a/instrumentation/kamon-kafka/src/main/scala/kamon/instrumentation/kafka/client/KafkaInstrumentation.scala b/instrumentation/kamon-kafka/src/main/scala/kamon/instrumentation/kafka/client/KafkaInstrumentation.scala index 139c49fc2..f1e1a9267 100644 --- a/instrumentation/kamon-kafka/src/main/scala/kamon/instrumentation/kafka/client/KafkaInstrumentation.scala +++ b/instrumentation/kamon-kafka/src/main/scala/kamon/instrumentation/kafka/client/KafkaInstrumentation.scala @@ -50,10 +50,12 @@ object KafkaInstrumentation { log.warn("W3C TraceContext propagation should be used only with identifier-scheme = double") } SpanPropagation.W3CTraceContext() - case fqcn => try ClassLoading.createInstance[KafkaPropagator](fqcn) catch { - case t: Throwable => - sys.error(s"Failed to create kafka propagator instance from FQCN [$fqcn]. Reason: ${t.getMessage}") - } + case fqcn => + try ClassLoading.createInstance[KafkaPropagator](fqcn) + catch { + case t: Throwable => + sys.error(s"Failed to create kafka propagator instance from FQCN [$fqcn]. Reason: ${t.getMessage}") + } } ) } @@ -68,7 +70,7 @@ object KafkaInstrumentation { implicit class Syntax(val cr: ConsumerRecord[_, _]) extends AnyVal { def context: Context = cr match { case hc: HasContext => hc.context - case _ => Context.Empty + case _ => Context.Empty } } @@ -190,14 +192,13 @@ object KafkaInstrumentation { consumerSpan.link(incomingSpan, Span.Link.Kind.FollowsFrom) } - // The additional context information will only be available when instrumentation is enabled. if (record.isInstanceOf[ConsumedRecordData]) { val consumerRecordData = record.asInstanceOf[ConsumedRecordData] // The consumer record data might be missing if the `ConsumerRecord` instance is created outside // of the instrumented paths. - if(consumerRecordData.consumerInfo() != null) { + if (consumerRecordData.consumerInfo() != null) { consumerSpan .tag("kafka.group-id", consumerRecordData.consumerInfo().groupId.getOrElse("unknown")) .tag("kafka.client-id", consumerRecordData.consumerInfo().clientId) @@ -219,7 +220,7 @@ object KafkaInstrumentation { * that was injected by Kamon while calling the poll method. */ def copyHiddenState(from: ConsumerRecord[_, _], to: ConsumerRecord[_, _]): ConsumerRecord[_, _] = { - if(from != null && to != null && from.isInstanceOf[ConsumedRecordData]) { + if (from != null && to != null && from.isInstanceOf[ConsumedRecordData]) { val fromRecordData = from.asInstanceOf[ConsumedRecordData] val toRecordData = to.asInstanceOf[ConsumedRecordData] toRecordData.set( diff --git a/instrumentation/kamon-kafka/src/main/scala/kamon/instrumentation/kafka/client/ProducerInstrumentation.scala b/instrumentation/kamon-kafka/src/main/scala/kamon/instrumentation/kafka/client/ProducerInstrumentation.scala index cb5e8551d..3da4806c1 100644 --- a/instrumentation/kamon-kafka/src/main/scala/kamon/instrumentation/kafka/client/ProducerInstrumentation.scala +++ b/instrumentation/kamon-kafka/src/main/scala/kamon/instrumentation/kafka/client/ProducerInstrumentation.scala @@ -43,15 +43,14 @@ final class ProducerCallback(callback: Callback, sendingSpan: Span, context: Con override def onCompletion(metadata: RecordMetadata, exception: Exception): Unit = { try { - if(exception != null) + if (exception != null) sendingSpan.fail(exception) else sendingSpan.tag("kafka.partition", metadata.partition()) - if(callback != null) + if (callback != null) Kamon.runWithContext(context)(callback.onCompletion(metadata, exception)) - } - finally { + } finally { sendingSpan.finish() } } diff --git a/instrumentation/kamon-kafka/src/main/scala/kamon/instrumentation/kafka/client/RecordProcessor.scala b/instrumentation/kamon-kafka/src/main/scala/kamon/instrumentation/kafka/client/RecordProcessor.scala index 20540cf1b..c4e023554 100644 --- a/instrumentation/kamon-kafka/src/main/scala/kamon/instrumentation/kafka/client/RecordProcessor.scala +++ b/instrumentation/kamon-kafka/src/main/scala/kamon/instrumentation/kafka/client/RecordProcessor.scala @@ -34,7 +34,12 @@ private[kafka] object RecordProcessor { * linked to it's bundled span (if any is present). Context (either new or inbound) containing consumer * span is then propagated with the record via `HasContext` mixin */ - def process[V, K](startTime: Instant, clientId: String, groupId: AnyRef, records: ConsumerRecords[K, V]): ConsumerRecords[K, V] = { + def process[V, K]( + startTime: Instant, + clientId: String, + groupId: AnyRef, + records: ConsumerRecords[K, V] + ): ConsumerRecords[K, V] = { if (!records.isEmpty) { val consumerInfo = ConsumerInfo(resolve(groupId), clientId) @@ -56,8 +61,8 @@ private[kafka] object RecordProcessor { * KafkaConsumer which versions < 2.5 relies on internal groupId: String and higher versions in Optional[String]. */ private def resolve(groupId: AnyRef): Option[String] = groupId match { - case opt: Optional[String] => if (opt.isPresent) Some(opt.get()) else None - case value: String => Option(value) - case _ => None - } + case opt: Optional[String] => if (opt.isPresent) Some(opt.get()) else None + case value: String => Option(value) + case _ => None + } } diff --git a/instrumentation/kamon-kafka/src/test/scala/kamon/instrumentation/kafka/client/KafkaClientsTracingInstrumentationSpec.scala b/instrumentation/kamon-kafka/src/test/scala/kamon/instrumentation/kafka/client/KafkaClientsTracingInstrumentationSpec.scala index a8a18948f..5e94eda48 100644 --- a/instrumentation/kamon-kafka/src/test/scala/kamon/instrumentation/kafka/client/KafkaClientsTracingInstrumentationSpec.scala +++ b/instrumentation/kamon-kafka/src/test/scala/kamon/instrumentation/kafka/client/KafkaClientsTracingInstrumentationSpec.scala @@ -38,14 +38,13 @@ import java.time.Duration import java.util.{Collections, Properties} class KafkaClientsTracingInstrumentationSpec extends AnyWordSpec with Matchers - with Eventually - with SpanSugar - with BeforeAndAfter - with InitAndStopKamonAfterAll - with Reconfigure - with OptionValues - with TestSpanReporting { - + with Eventually + with SpanSugar + with BeforeAndAfter + with InitAndStopKamonAfterAll + with Reconfigure + with OptionValues + with TestSpanReporting { implicit val stringSerializer: Serializer[String] = new StringSerializer implicit val stringDeserializer: Deserializer[String] = new StringDeserializer @@ -125,8 +124,12 @@ class KafkaClientsTracingInstrumentationSpec extends AnyWordSpec with Matchers } } - "create a Producer/Consumer Span when publish/consume a message without follow-strategy and expect a linked span" in new SpanReportingTestScope(reporter) { - Kamon.reconfigure(ConfigFactory.parseString("kamon.instrumentation.kafka.client.tracing.continue-trace-on-consumer = false").withFallback(Kamon.config())) + "create a Producer/Consumer Span when publish/consume a message without follow-strategy and expect a linked span" in new SpanReportingTestScope( + reporter + ) { + Kamon.reconfigure(ConfigFactory.parseString( + "kamon.instrumentation.kafka.client.tracing.continue-trace-on-consumer = false" + ).withFallback(Kamon.config())) val testTopicName = "producer-consumer-span-with-links" publishStringMessageToKafka(testTopicName, "Hello world!!!") consumeFirstRawRecord(testTopicName).value() shouldBe "Hello world!!!" @@ -161,12 +164,15 @@ class KafkaClientsTracingInstrumentationSpec extends AnyWordSpec with Matchers assertNoSpansReported() } - "create a Producer/Consumer Span when publish/consume a message with delayed spans" in new SpanReportingTestScope(reporter) { + "create a Producer/Consumer Span when publish/consume a message with delayed spans" in new SpanReportingTestScope( + reporter + ) { Kamon.reconfigure(ConfigFactory.parseString( """ |kamon.instrumentation.kafka.client.tracing.use-delayed-spans = true |kamon.instrumentation.kafka.client.tracing.continue-trace-on-consumer = false - """.stripMargin).withFallback(Kamon.config())) + """.stripMargin + ).withFallback(Kamon.config())) KafkaInstrumentation.settings.useDelayedSpans shouldBe true val testTopicName = "producer-consumer-span-with-delayed" @@ -205,7 +211,9 @@ class KafkaClientsTracingInstrumentationSpec extends AnyWordSpec with Matchers assertNoSpansReported() } - "create a Producer/Consumer Span when publish/consume a message with w3c format" in new SpanReportingTestScope(reporter) { + "create a Producer/Consumer Span when publish/consume a message with w3c format" in new SpanReportingTestScope( + reporter + ) { applyConfig("kamon.trace.identifier-scheme = double") applyConfig("kamon.instrumentation.kafka.client.tracing.propagator = w3c") @@ -244,8 +252,12 @@ class KafkaClientsTracingInstrumentationSpec extends AnyWordSpec with Matchers } } - "create a Producer/Consumer Span when publish/consume a message with custom format" in new SpanReportingTestScope(reporter) { - applyConfig("kamon.instrumentation.kafka.client.tracing.propagator = kamon.instrumentation.kafka.testutil.CustomPropagationImplementation") + "create a Producer/Consumer Span when publish/consume a message with custom format" in new SpanReportingTestScope( + reporter + ) { + applyConfig( + "kamon.instrumentation.kafka.client.tracing.propagator = kamon.instrumentation.kafka.testutil.CustomPropagationImplementation" + ) val testTopicName = "custom-context-propagation" publishStringMessageToKafka(testTopicName, "Hello world!!!") diff --git a/instrumentation/kamon-kafka/src/test/scala/kamon/instrumentation/kafka/testutil/CustomPropagationImplementation.scala b/instrumentation/kamon-kafka/src/test/scala/kamon/instrumentation/kafka/testutil/CustomPropagationImplementation.scala index d8c852054..7e5e0a6b8 100644 --- a/instrumentation/kamon-kafka/src/test/scala/kamon/instrumentation/kafka/testutil/CustomPropagationImplementation.scala +++ b/instrumentation/kamon-kafka/src/test/scala/kamon/instrumentation/kafka/testutil/CustomPropagationImplementation.scala @@ -16,12 +16,13 @@ class CustomPropagationImplementation extends KafkaPropagator { traceIdStr = new String(traceId, "utf-8") spanId <- Option(medium.lastHeader("x-span-id")).map(_.value()) spanIdStr = new String(spanId, "utf-8") - sampled <- Option(medium.lastHeader("x-trace-sampled")).map(_.value()).map{ - case Array(1) => SamplingDecision.Sample - case Array(0) => SamplingDecision.DoNotSample - case _ => SamplingDecision.Unknown + sampled <- Option(medium.lastHeader("x-trace-sampled")).map(_.value()).map { + case Array(1) => SamplingDecision.Sample + case Array(0) => SamplingDecision.DoNotSample + case _ => SamplingDecision.Unknown } - span = Span.Remote(Identifier(spanIdStr, spanId), Identifier.Empty, Trace(Identifier(traceIdStr, traceId), sampled)) + span = + Span.Remote(Identifier(spanIdStr, spanId), Identifier.Empty, Trace(Identifier(traceIdStr, traceId), sampled)) } yield context.withEntry(Span.Key, span) contextWithParent.getOrElse(context) @@ -36,4 +37,4 @@ class CustomPropagationImplementation extends KafkaPropagator { medium.add("x-trace-sampled", if (span.trace.samplingDecision == SamplingDecision.Sample) Array(1) else Array(0)) } } -} \ No newline at end of file +} diff --git a/instrumentation/kamon-kafka/src/test/scala/kamon/instrumentation/kafka/testutil/DotFileGenerator.scala b/instrumentation/kamon-kafka/src/test/scala/kamon/instrumentation/kafka/testutil/DotFileGenerator.scala index 009f88060..a639cfd3f 100644 --- a/instrumentation/kamon-kafka/src/test/scala/kamon/instrumentation/kafka/testutil/DotFileGenerator.scala +++ b/instrumentation/kamon-kafka/src/test/scala/kamon/instrumentation/kafka/testutil/DotFileGenerator.scala @@ -51,10 +51,9 @@ object DotFileGenerator { bw.close() val cmd = "dot -Tjpeg $FILENAME.dot | feh -".replace("$FILENAME", filename) val rc = executeShellCommand("sh", "-c", cmd) - if(rc == 0) { + if (rc == 0) { println(s"DotFileGenerator: wrote and processed file: ${file.getAbsolutePath}") - } - else { + } else { println(s"DOT generation failed! rc=$rc, cmd='$cmd'") } } @@ -70,7 +69,7 @@ object DotFileGenerator { } import java.util.concurrent.Executors val builder = new ProcessBuilder - builder.command(cmd :_ *) + builder.command(cmd: _*) builder.directory(new File(".")) val process = builder.start val streamGobbler = new StreamGobbler(process.getInputStream, println) @@ -78,10 +77,9 @@ object DotFileGenerator { process.waitFor } - private def toDotString(spans: List[Span.Finished], name: String, allTags: Boolean = true): String = { - def filterTags(span: Span.Finished) : List[(String,String)]= { - if(allTags) { + def filterTags(span: Span.Finished): List[(String, String)] = { + if (allTags) { (span.tags.iterator.map(t => t.key -> Tag.unwrapValue(t).toString) ++ span.metricTags.iterator.map(t => s"metric - ${t.key}" -> Tag.unwrapValue(t).toString)).toList } else { @@ -90,7 +88,9 @@ object DotFileGenerator { "span.kind" -> span.tags.get(plain("span.kind")), "hasError" -> span.hasError.toString ) - commonTags ++ optionalMetricTags.map(t => t -> Option(span.tags.get(plain(t)))).filter(_._2.isDefined).map(t => (t._1, t._2.get)) + commonTags ++ optionalMetricTags.map(t => t -> Option(span.tags.get(plain(t)))).filter(_._2.isDefined).map(t => + (t._1, t._2.get) + ) } } def getLabel(s: Span.Finished) = { @@ -108,11 +108,11 @@ object DotFileGenerator { val comp = s.metricTags.get(plain("component")) val opName = s.operationName (comp, opName) match { - case ("kafka.stream", _) => ("box", "rounded,bold") + case ("kafka.stream", _) => ("box", "rounded,bold") case ("kafka.stream.node", _) => ("box", "rounded") - case (_, "poll") => ("box", "dotted") - case (_, "send") => ("box", "dotted") - case _ => ("oval", "solid") + case (_, "poll") => ("box", "dotted") + case (_, "send") => ("box", "dotted") + case _ => ("oval", "solid") } } @@ -122,7 +122,7 @@ object DotFileGenerator { } def createNodes = { - spans.map{s => + spans.map { s => createNode(s) }.mkString("\n") } @@ -139,16 +139,20 @@ object DotFileGenerator { spans.map(s => { val sourceNode = getParent(s) - s""" "$sourceNode" -> "${s.id.string}" [style="${if(sourceNode==StartNode) "dotted" else "bold"}"];""" + s""" "$sourceNode" -> "${s.id.string}" [style="${if (sourceNode == StartNode) "dotted" else "bold"}"];""" }).mkString("\n") } def createLinkEdges = { - spans.flatMap(sTarget => sTarget.links.filter(_.spanId.string != "").map(sSource => s""" "${sSource.spanId.string}" -> "${sTarget.id.string}" [style="dashed"];""")).mkString("\n") + spans.flatMap(sTarget => + sTarget.links.filter(_.spanId.string != "").map(sSource => + s""" "${sSource.spanId.string}" -> "${sTarget.id.string}" [style="dashed"];""" + ) + ).mkString("\n") } def createSubgraphsPerTrace: String = { - spans.map(_.trace.id.string).distinct.map{ traceId => + spans.map(_.trace.id.string).distinct.map { traceId => s""" | subgraph cluster_$traceId { | label="Trace $traceId"; diff --git a/instrumentation/kamon-kafka/src/test/scala/kamon/instrumentation/kafka/testutil/SpanReportingTestScope.scala b/instrumentation/kamon-kafka/src/test/scala/kamon/instrumentation/kafka/testutil/SpanReportingTestScope.scala index eac01f557..63b4eedc6 100644 --- a/instrumentation/kamon-kafka/src/test/scala/kamon/instrumentation/kafka/testutil/SpanReportingTestScope.scala +++ b/instrumentation/kamon-kafka/src/test/scala/kamon/instrumentation/kafka/testutil/SpanReportingTestScope.scala @@ -19,11 +19,11 @@ import kamon.trace.Span import org.scalatest.concurrent.{Eventually, PatienceConfiguration} import org.scalatest.matchers.should.Matchers -abstract class SpanReportingTestScope(_reporter: TestSpanReporter.BufferingSpanReporter) extends Eventually with Matchers { +abstract class SpanReportingTestScope(_reporter: TestSpanReporter.BufferingSpanReporter) extends Eventually + with Matchers { private var _reportedSpans: List[Span.Finished] = Nil _reporter.clear() - def reportedSpans: List[Span.Finished] = _reportedSpans def assertNoSpansReported(): Unit = @@ -33,7 +33,7 @@ abstract class SpanReportingTestScope(_reporter: TestSpanReporter.BufferingSpanR def doIt(prevNumReportedSpans: Int): Unit = { Thread.sleep(waitBetweenPollInMs) collectReportedSpans() - if(reportedSpans.size != prevNumReportedSpans) + if (reportedSpans.size != prevNumReportedSpans) doIt(reportedSpans.size) } doIt(reportedSpans.size) @@ -45,7 +45,7 @@ abstract class SpanReportingTestScope(_reporter: TestSpanReporter.BufferingSpanR _reportedSpans.size shouldBe numOfExpectedSpans } Thread.sleep(300) - if(_reporter.nextSpan().isDefined) { + if (_reporter.nextSpan().isDefined) { fail(s"Expected only $numOfExpectedSpans spans to be reported, but got more!") } } diff --git a/instrumentation/kamon-lagom/src/main/scala/kamon/instrumentation/lagom/CircuitBreakerMetricsProviderImpl.scala b/instrumentation/kamon-lagom/src/main/scala/kamon/instrumentation/lagom/CircuitBreakerMetricsProviderImpl.scala index 920955952..d6f9a7f46 100644 --- a/instrumentation/kamon-lagom/src/main/scala/kamon/instrumentation/lagom/CircuitBreakerMetricsProviderImpl.scala +++ b/instrumentation/kamon-lagom/src/main/scala/kamon/instrumentation/lagom/CircuitBreakerMetricsProviderImpl.scala @@ -30,7 +30,7 @@ object CircuitBreakerMetricsImpl { } class CircuitBreakerMetricsImpl(val breakerId: String, provider: CircuitBreakerMetricsProviderImpl) - extends CircuitBreakerMetrics { + extends CircuitBreakerMetrics { import CircuitBreakerMetricsImpl._ private val log = Logger(getClass) diff --git a/instrumentation/kamon-lagom/src/main/scala/kamon/instrumentation/lagom/LagomMetrics.scala b/instrumentation/kamon-lagom/src/main/scala/kamon/instrumentation/lagom/LagomMetrics.scala index 3f46786a6..cfde06868 100644 --- a/instrumentation/kamon-lagom/src/main/scala/kamon/instrumentation/lagom/LagomMetrics.scala +++ b/instrumentation/kamon-lagom/src/main/scala/kamon/instrumentation/lagom/LagomMetrics.scala @@ -18,14 +18,16 @@ object LagomMetrics { description = "Call duration timer of Lagom Circuit Breakers" ) - class CircuitBreakerInstruments(circuitBreaker: String, tags: TagSet) extends InstrumentGroup(tags.withTag("cb.name", circuitBreaker)) { + class CircuitBreakerInstruments(circuitBreaker: String, tags: TagSet) + extends InstrumentGroup(tags.withTag("cb.name", circuitBreaker)) { val state: Gauge = register(CBState) - val okTimer : Timer = register(CBCallDuration, "status_code", "Ok") + val okTimer: Timer = register(CBCallDuration, "status_code", "Ok") val errorTagSet: TagSet = TagSet.of("status_code", "Error") - val errorTimer : Timer = register(CBCallDuration, errorTagSet) - val openTimer : Timer = register(CBCallDuration, errorTagSet.withTag("exception.type", "CircuitBreakerOpenException")) - val timeoutTimer : Timer = register(CBCallDuration, errorTagSet.withTag("exception.type", "TimeoutException")) + val errorTimer: Timer = register(CBCallDuration, errorTagSet) + val openTimer: Timer = + register(CBCallDuration, errorTagSet.withTag("exception.type", "CircuitBreakerOpenException")) + val timeoutTimer: Timer = register(CBCallDuration, errorTagSet.withTag("exception.type", "TimeoutException")) } } diff --git a/instrumentation/kamon-logback/src/main/scala/kamon/instrumentation/logback/LogbackInstrumentation.scala b/instrumentation/kamon-logback/src/main/scala/kamon/instrumentation/logback/LogbackInstrumentation.scala index 595c8ae6e..b9e7f888f 100644 --- a/instrumentation/kamon-logback/src/main/scala/kamon/instrumentation/logback/LogbackInstrumentation.scala +++ b/instrumentation/kamon-logback/src/main/scala/kamon/instrumentation/logback/LogbackInstrumentation.scala @@ -32,7 +32,6 @@ import java.util.concurrent.Callable import scala.annotation.static import scala.collection.JavaConverters._ - class LogbackInstrumentation extends InstrumentationBuilder { onSubTypesOf("ch.qos.logback.core.spi.DeferredProcessingAware") @@ -116,13 +115,14 @@ object GetPropertyMapMethodInterceptor { settings.mdcCopyKeys.foreach { key => currentContext.get(Context.key[Any](key, "")) match { - case Some(value) if value.toString.nonEmpty => MDC.put(key, value.toString) + case Some(value) if value.toString.nonEmpty => MDC.put(key, value.toString) case keyValue if keyValue != null && keyValue.toString.nonEmpty => MDC.put(key, keyValue.toString) - case _ => // Just ignore the nulls and empty strings + case _ => // Just ignore the nulls and empty strings } } - try callable.call() finally { + try callable.call() + finally { if (mdcContextMapBeforePropagation != null) { MDC.setContextMap(mdcContextMapBeforePropagation) } else { // a null contextMap is possible and means 'empty' diff --git a/instrumentation/kamon-logback/src/main/scala/kamon/instrumentation/logback/LogbackMetrics.scala b/instrumentation/kamon-logback/src/main/scala/kamon/instrumentation/logback/LogbackMetrics.scala index 8c91e4e90..8138e37ac 100644 --- a/instrumentation/kamon-logback/src/main/scala/kamon/instrumentation/logback/LogbackMetrics.scala +++ b/instrumentation/kamon-logback/src/main/scala/kamon/instrumentation/logback/LogbackMetrics.scala @@ -20,7 +20,7 @@ import kamon.Kamon object LogbackMetrics { - val LogEvents = Kamon.counter ( + val LogEvents = Kamon.counter( name = "log.events", description = "Counts the number of log events per level" ) diff --git a/instrumentation/kamon-logback/src/main/scala/kamon/instrumentation/logback/tools/ContextEntryConverter.scala b/instrumentation/kamon-logback/src/main/scala/kamon/instrumentation/logback/tools/ContextEntryConverter.scala index 45df3a920..13c05a8d0 100644 --- a/instrumentation/kamon-logback/src/main/scala/kamon/instrumentation/logback/tools/ContextEntryConverter.scala +++ b/instrumentation/kamon-logback/src/main/scala/kamon/instrumentation/logback/tools/ContextEntryConverter.scala @@ -29,15 +29,15 @@ class ContextEntryConverter extends ClassicConverter { super.start() val firstOption = getFirstOption() - if(firstOption != null && firstOption.nonEmpty) { + if (firstOption != null && firstOption.nonEmpty) { val optionParts = firstOption.split(':') - _default = if(optionParts.length > 1) optionParts(1) else "" + _default = if (optionParts.length > 1) optionParts(1) else "" _entryKey = Context.key(optionParts(0), _default) } } override def convert(event: ILoggingEvent): String = { - if(_entryKey != null) { + if (_entryKey != null) { val context = Kamon.currentContext() context.get(_entryKey).toString } else _default diff --git a/instrumentation/kamon-logback/src/main/scala/kamon/instrumentation/logback/tools/ContextTagConverter.scala b/instrumentation/kamon-logback/src/main/scala/kamon/instrumentation/logback/tools/ContextTagConverter.scala index 508c1b3c5..ffd960ecf 100644 --- a/instrumentation/kamon-logback/src/main/scala/kamon/instrumentation/logback/tools/ContextTagConverter.scala +++ b/instrumentation/kamon-logback/src/main/scala/kamon/instrumentation/logback/tools/ContextTagConverter.scala @@ -29,15 +29,15 @@ class ContextTagConverter extends ClassicConverter { super.start() val firstOption = getFirstOption() - if(firstOption != null && firstOption.nonEmpty) { + if (firstOption != null && firstOption.nonEmpty) { val optionParts = firstOption.split(':') _tagName = optionParts(0) - _default = if(optionParts.length > 1) optionParts(1) else "" + _default = if (optionParts.length > 1) optionParts(1) else "" } } override def convert(event: ILoggingEvent): String = { - if(_tagName != null) { + if (_tagName != null) { val context = Kamon.currentContext() context.tags.get(coerce(_tagName, _default)) } else _default diff --git a/instrumentation/kamon-logback/src/main/scala/kamon/instrumentation/logback/tools/EntriesCounterAppender.scala b/instrumentation/kamon-logback/src/main/scala/kamon/instrumentation/logback/tools/EntriesCounterAppender.scala index f4a606150..ca34e8599 100644 --- a/instrumentation/kamon-logback/src/main/scala/kamon/instrumentation/logback/tools/EntriesCounterAppender.scala +++ b/instrumentation/kamon-logback/src/main/scala/kamon/instrumentation/logback/tools/EntriesCounterAppender.scala @@ -28,13 +28,13 @@ class EntriesCounterAppender extends UnsynchronizedAppenderBase[ILoggingEvent] { private val _countersPerLevel = TrieMap.empty[Int, Counter] protected def append(event: ILoggingEvent): Unit = { - _countersPerLevel.getOrElseUpdate(event.getLevel.toInt, { - LogbackMetrics.LogEvents.withTags(TagSet.builder() - .add("component", "logback") - .add("level", event.getLevel.levelStr) - .build() - ) - }).increment() + _countersPerLevel.getOrElseUpdate( + event.getLevel.toInt, { + LogbackMetrics.LogEvents.withTags(TagSet.builder() + .add("component", "logback") + .add("level", event.getLevel.levelStr) + .build()) + } + ).increment() } } - diff --git a/instrumentation/kamon-logback/src/main/scala/kamon/instrumentation/logback/tools/SpanIDConverter.scala b/instrumentation/kamon-logback/src/main/scala/kamon/instrumentation/logback/tools/SpanIDConverter.scala index 96dd08c2f..e10d52880 100644 --- a/instrumentation/kamon-logback/src/main/scala/kamon/instrumentation/logback/tools/SpanIDConverter.scala +++ b/instrumentation/kamon-logback/src/main/scala/kamon/instrumentation/logback/tools/SpanIDConverter.scala @@ -27,7 +27,7 @@ class SpanIDConverter extends ClassicConverter { val currentSpan = Kamon.currentSpan() val spanID = currentSpan.id - if(spanID == Identifier.Empty) + if (spanID == Identifier.Empty) "undefined" else spanID.string diff --git a/instrumentation/kamon-logback/src/main/scala/kamon/instrumentation/logback/tools/SpanOperationNameConverter.scala b/instrumentation/kamon-logback/src/main/scala/kamon/instrumentation/logback/tools/SpanOperationNameConverter.scala index 3ae363ba6..ac071b639 100644 --- a/instrumentation/kamon-logback/src/main/scala/kamon/instrumentation/logback/tools/SpanOperationNameConverter.scala +++ b/instrumentation/kamon-logback/src/main/scala/kamon/instrumentation/logback/tools/SpanOperationNameConverter.scala @@ -27,7 +27,7 @@ class SpanOperationNameConverter extends ClassicConverter { val currentSpan = Kamon.currentSpan() val spanOperationName = currentSpan.operationName() - if(spanOperationName.equals("empty")) + if (spanOperationName.equals("empty")) "undefined" else spanOperationName diff --git a/instrumentation/kamon-logback/src/main/scala/kamon/instrumentation/logback/tools/TraceIDConverter.scala b/instrumentation/kamon-logback/src/main/scala/kamon/instrumentation/logback/tools/TraceIDConverter.scala index 99d4c5401..f79b742f2 100644 --- a/instrumentation/kamon-logback/src/main/scala/kamon/instrumentation/logback/tools/TraceIDConverter.scala +++ b/instrumentation/kamon-logback/src/main/scala/kamon/instrumentation/logback/tools/TraceIDConverter.scala @@ -27,7 +27,7 @@ class TraceIDConverter extends ClassicConverter { val currentSpan = Kamon.currentSpan() val traceID = currentSpan.trace.id - if(traceID == Identifier.Empty) + if (traceID == Identifier.Empty) "undefined" else traceID.string diff --git a/instrumentation/kamon-logback/src/test/scala/kamon/instrumentation/logback/LogbackEntriesCounterAppenderSpec.scala b/instrumentation/kamon-logback/src/test/scala/kamon/instrumentation/logback/LogbackEntriesCounterAppenderSpec.scala index cfc2d84fc..6f9173859 100644 --- a/instrumentation/kamon-logback/src/test/scala/kamon/instrumentation/logback/LogbackEntriesCounterAppenderSpec.scala +++ b/instrumentation/kamon-logback/src/test/scala/kamon/instrumentation/logback/LogbackEntriesCounterAppenderSpec.scala @@ -12,7 +12,8 @@ import org.scalatest.concurrent.Eventually import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec -class LogbackEntriesCounterAppenderSpec extends AnyWordSpec with Matchers with InstrumentInspection.Syntax with Eventually { +class LogbackEntriesCounterAppenderSpec extends AnyWordSpec with Matchers with InstrumentInspection.Syntax + with Eventually { "LogbackEntriesCounterAppender" when { "a event is logged" should { diff --git a/instrumentation/kamon-logback/src/test/scala/kamon/instrumentation/logback/LogbackMdcCopyingSpec.scala b/instrumentation/kamon-logback/src/test/scala/kamon/instrumentation/logback/LogbackMdcCopyingSpec.scala index 96dab953c..7a56c653a 100644 --- a/instrumentation/kamon-logback/src/test/scala/kamon/instrumentation/logback/LogbackMdcCopyingSpec.scala +++ b/instrumentation/kamon-logback/src/test/scala/kamon/instrumentation/logback/LogbackMdcCopyingSpec.scala @@ -55,14 +55,17 @@ class LogbackMdcCopyingSpec extends AnyWordSpec with Matchers with Eventually wi } "copy context information into the MDC" in { - val memoryAppender = buildMemoryAppender(configurator,s"%X{${LogbackInstrumentation.settings().mdcTraceIdKey}} %X{${LogbackInstrumentation.settings().mdcSpanIdKey}} %X{mdc_key}") + val memoryAppender = buildMemoryAppender( + configurator, + s"%X{${LogbackInstrumentation.settings().mdcTraceIdKey}} %X{${LogbackInstrumentation.settings().mdcSpanIdKey}} %X{mdc_key}" + ) val span = Kamon.spanBuilder("my-span").start() val traceID = span.trace.id val spanID = span.id val contextWithSpan = Context.of(Span.Key, span) - MDC.put("mdc_key","mdc_value") + MDC.put("mdc_key", "mdc_value") Kamon.runWithContext(contextWithSpan) { memoryAppender.doAppend(createLoggingEvent(context)) } @@ -73,12 +76,12 @@ class LogbackMdcCopyingSpec extends AnyWordSpec with Matchers with Eventually wi } "copy context tags into the MDC" in { - val memoryAppender = buildMemoryAppender(configurator,s"%X{my-tag} %X{mdc_key}") + val memoryAppender = buildMemoryAppender(configurator, s"%X{my-tag} %X{mdc_key}") val span = Kamon.spanBuilder("my-span").start() val contextWithSpan = Context.of("my-tag", "my-value") - MDC.put("mdc_key","mdc_value") + MDC.put("mdc_key", "mdc_value") Kamon.runWithContext(contextWithSpan) { memoryAppender.doAppend(createLoggingEvent(context)) } @@ -91,7 +94,8 @@ class LogbackMdcCopyingSpec extends AnyWordSpec with Matchers with Eventually wi Kamon.reconfigure( ConfigFactory .parseString("kamon.instrumentation.logback.mdc.copy.entries = [ testKey1, testKey2 ]") - .withFallback(ConfigFactory.defaultReference())) + .withFallback(ConfigFactory.defaultReference()) + ) val memoryAppender = buildMemoryAppender(configurator, "%X{testKey1} %X{testKey2}") val span = Kamon.spanBuilder("my-span").start() @@ -112,7 +116,8 @@ class LogbackMdcCopyingSpec extends AnyWordSpec with Matchers with Eventually wi Kamon.reconfigure( ConfigFactory .parseString("kamon.logback.mdc-traced-broadcast-keys = [ testKey1, testKey2 ]") - .withFallback(ConfigFactory.defaultReference())) + .withFallback(ConfigFactory.defaultReference()) + ) val memoryAppender = buildMemoryAppender(configurator, "%X{testKey1} %X{testKey2}") val span = Kamon.spanBuilder("my-span").start() @@ -126,7 +131,6 @@ class LogbackMdcCopyingSpec extends AnyWordSpec with Matchers with Eventually wi memoryAppender.getLastLine shouldBe " " } - "ignore copying information into the MDC when disabled" in { Kamon.reconfigure( ConfigFactory @@ -134,7 +138,8 @@ class LogbackMdcCopyingSpec extends AnyWordSpec with Matchers with Eventually wi .withFallback(ConfigFactory.defaultReference()) ) - val memoryAppender = buildMemoryAppender(configurator,s"%X{${LogbackInstrumentation.settings().mdcTraceIdKey}}") + val memoryAppender = + buildMemoryAppender(configurator, s"%X{${LogbackInstrumentation.settings().mdcTraceIdKey}}") val span = Kamon.spanBuilder("my-span").start() val contextWithSpan = Context.of(Span.Key, span) @@ -170,7 +175,8 @@ class LogbackMdcCopyingSpec extends AnyWordSpec with Matchers with Eventually wi } "allow using Context entries in the logging patterns" in { - val memoryAppender = buildMemoryAppender(configurator, "%contextEntry{oneEntry} %contextEntry{otherEntry:default}") + val memoryAppender = + buildMemoryAppender(configurator, "%contextEntry{oneEntry} %contextEntry{otherEntry:default}") val contextWithTags = Context.of(Context.key[String]("oneEntry", null), "oneValue") Kamon.runWithContext(contextWithTags)(memoryAppender.doAppend(createLoggingEvent(context))) diff --git a/instrumentation/kamon-logback/src/test/scala/kamon/instrumentation/logback/package.scala b/instrumentation/kamon-logback/src/test/scala/kamon/instrumentation/logback/package.scala index 326afbc72..f50bb7d1d 100644 --- a/instrumentation/kamon-logback/src/test/scala/kamon/instrumentation/logback/package.scala +++ b/instrumentation/kamon-logback/src/test/scala/kamon/instrumentation/logback/package.scala @@ -7,7 +7,13 @@ import ch.qos.logback.classic.spi.{ILoggingEvent, LoggingEvent} import ch.qos.logback.classic.{AsyncAppender, Level, LoggerContext} import ch.qos.logback.core.Appender import ch.qos.logback.core.util.OptionHelper -import kamon.instrumentation.logback.tools.{ContextEntryConverter, ContextTagConverter, SpanIDConverter, SpanOperationNameConverter, TraceIDConverter} +import kamon.instrumentation.logback.tools.{ + ContextEntryConverter, + ContextTagConverter, + SpanIDConverter, + SpanOperationNameConverter, + TraceIDConverter +} import kamon.logback.util.LogbackConfigurator import org.slf4j.impl.StaticLoggerBinder @@ -21,7 +27,8 @@ package object logback { configurator.conversionRule("contextTag", classOf[ContextTagConverter]) configurator.conversionRule("contextEntry", classOf[ContextEntryConverter]) - def buildMemoryAppender(config: LogbackConfigurator): LogbackMemoryAppender = buildMemoryAppender(config,"%traceID %spanID %spanOperationName") + def buildMemoryAppender(config: LogbackConfigurator): LogbackMemoryAppender = + buildMemoryAppender(config, "%traceID %spanID %spanOperationName") def buildMemoryAppender(config: LogbackConfigurator, logPattern: String): LogbackMemoryAppender = { val appender = new LogbackMemoryAppender() @@ -49,6 +56,9 @@ package object logback { new LoggingEvent(this.getClass.getName, loggerContext.getLogger("ROOT"), level, "test message", null, null) } - def logMany(times: Int, level: Level)(implicit appender: Appender[ILoggingEvent], loggerContext: LoggerContext): Unit = - for(_ <- 1 to times) { appender.doAppend(createLoggingEvent(context, level)) } + def logMany(times: Int, level: Level)(implicit + appender: Appender[ILoggingEvent], + loggerContext: LoggerContext + ): Unit = + for (_ <- 1 to times) { appender.doAppend(createLoggingEvent(context, level)) } } diff --git a/instrumentation/kamon-mongo-legacy/src/main/scala/kamon/instrumentation/legacy/mongo/MongoClientInstrumentation.scala b/instrumentation/kamon-mongo-legacy/src/main/scala/kamon/instrumentation/legacy/mongo/MongoClientInstrumentation.scala index 456a7ed1e..2256b2600 100644 --- a/instrumentation/kamon-mongo-legacy/src/main/scala/kamon/instrumentation/legacy/mongo/MongoClientInstrumentation.scala +++ b/instrumentation/kamon-mongo-legacy/src/main/scala/kamon/instrumentation/legacy/mongo/MongoClientInstrumentation.scala @@ -94,7 +94,6 @@ class MongoClientInstrumentation extends InstrumentationBuilder { } - class CopyOperationNameIntoMixedBulkWriteOperation object CopyOperationNameIntoMixedBulkWriteOperation { @@ -103,7 +102,7 @@ object CopyOperationNameIntoMixedBulkWriteOperation { def exit(@Advice.Return writeOperation: Any, @Advice.Origin("#m") methodName: String): Unit = { writeOperation match { case hon: HasOperationName => hon.setName(methodName) - case _ => + case _ => } } } diff --git a/instrumentation/kamon-mongo-legacy/src/test/scala/kamon/instrumentation/mongo/EmbeddedMongoTest.scala b/instrumentation/kamon-mongo-legacy/src/test/scala/kamon/instrumentation/mongo/EmbeddedMongoTest.scala index ea06b2158..7eb4b2f09 100644 --- a/instrumentation/kamon-mongo-legacy/src/test/scala/kamon/instrumentation/mongo/EmbeddedMongoTest.scala +++ b/instrumentation/kamon-mongo-legacy/src/test/scala/kamon/instrumentation/mongo/EmbeddedMongoTest.scala @@ -45,5 +45,4 @@ abstract class EmbeddedMongoTest(port: Int) extends AnyWordSpec with BeforeAndAf super.afterAll() } - } diff --git a/instrumentation/kamon-mongo-legacy/src/test/scala/kamon/instrumentation/mongo/MongoScalaDriverInstrumentationSpec.scala b/instrumentation/kamon-mongo-legacy/src/test/scala/kamon/instrumentation/mongo/MongoScalaDriverInstrumentationSpec.scala index e188da095..c09c3b153 100644 --- a/instrumentation/kamon-mongo-legacy/src/test/scala/kamon/instrumentation/mongo/MongoScalaDriverInstrumentationSpec.scala +++ b/instrumentation/kamon-mongo-legacy/src/test/scala/kamon/instrumentation/mongo/MongoScalaDriverInstrumentationSpec.scala @@ -216,7 +216,9 @@ class MongoScalaDriverInstrumentationSpec extends EmbeddedMongoTest(port = 4445) tools.insertOne(Document("name" -> "kamon", "reduce" -> true, "license" -> "apache", "value" -> 100)).consume() tools.insertOne(Document("name" -> "zipkin", "reduce" -> true, "license" -> "apache", "value" -> 100)).consume() - tools.insertOne(Document("name" -> "prometheus", "reduce" -> true, "license" -> "apache", "value" -> 100)).consume() + tools.insertOne( + Document("name" -> "prometheus", "reduce" -> true, "license" -> "apache", "value" -> 100) + ).consume() tools.insertOne(Document("name" -> "linux", "reduce" -> true, "license" -> "gpl", "value" -> 100)).consume() tools.mapReduce( @@ -229,7 +231,6 @@ class MongoScalaDriverInstrumentationSpec extends EmbeddedMongoTest(port = 4445) | } |} """.stripMargin, - """ |function(key, values) { | return Array.sum(values) @@ -253,7 +254,9 @@ class MongoScalaDriverInstrumentationSpec extends EmbeddedMongoTest(port = 4445) tools.insertOne(Document("name" -> "kamon", "reduce" -> true, "license" -> "apache", "value" -> 100)).consume() tools.insertOne(Document("name" -> "zipkin", "reduce" -> true, "license" -> "apache", "value" -> 100)).consume() - tools.insertOne(Document("name" -> "prometheus", "reduce" -> true, "license" -> "apache", "value" -> 100)).consume() + tools.insertOne( + Document("name" -> "prometheus", "reduce" -> true, "license" -> "apache", "value" -> 100) + ).consume() tools.insertOne(Document("name" -> "linux", "reduce" -> true, "license" -> "gpl", "value" -> 100)).consume() tools.mapReduce( @@ -266,7 +269,6 @@ class MongoScalaDriverInstrumentationSpec extends EmbeddedMongoTest(port = 4445) | } |} """.stripMargin, - """ |function(key, values) { | return Array.sum(values) @@ -336,10 +338,8 @@ class MongoScalaDriverInstrumentationSpec extends EmbeddedMongoTest(port = 4445) } } - } - implicit class RichSingleObservable[T](observable: Observable[T]) { // Shorthand for just consuming results from an observable. diff --git a/instrumentation/kamon-mongo-legacy/src/test/scala/kamon/instrumentation/mongo/MongoSyncDriverInstrumentationSpec.scala b/instrumentation/kamon-mongo-legacy/src/test/scala/kamon/instrumentation/mongo/MongoSyncDriverInstrumentationSpec.scala index a92372250..524207fe7 100644 --- a/instrumentation/kamon-mongo-legacy/src/test/scala/kamon/instrumentation/mongo/MongoSyncDriverInstrumentationSpec.scala +++ b/instrumentation/kamon-mongo-legacy/src/test/scala/kamon/instrumentation/mongo/MongoSyncDriverInstrumentationSpec.scala @@ -38,7 +38,7 @@ class MongoSyncDriverInstrumentationSpec extends EmbeddedMongoTest(port = 4445) span } - while(aggregateResults.hasNext) { + while (aggregateResults.hasNext) { aggregateResults.next() } @@ -135,7 +135,7 @@ class MongoSyncDriverInstrumentationSpec extends EmbeddedMongoTest(port = 4445) } // We are exhausting the iterator to for the getMore operation to happen - while(results.hasNext) { + while (results.hasNext) { results.next() } @@ -225,10 +225,22 @@ class MongoSyncDriverInstrumentationSpec extends EmbeddedMongoTest(port = 4445) // fetching all the results from Mongo. If that behavior changes we should make sure that any getMore // operations are covered by this test. - tools.insertOne(new Document("name", "kamon").append("reduce", true).append("license", "apache").append("value", 100)) - tools.insertOne(new Document("name", "zipkin").append("reduce", true).append("license", "apache").append("value", 100)) - tools.insertOne(new Document("name", "prometheus").append("reduce", true).append("license", "apache").append("value", 100)) - tools.insertOne(new Document("name", "linux").append("reduce", true).append("license", "gpl").append("value", 100)) + tools.insertOne(new Document("name", "kamon").append("reduce", true).append("license", "apache").append( + "value", + 100 + )) + tools.insertOne(new Document("name", "zipkin").append("reduce", true).append("license", "apache").append( + "value", + 100 + )) + tools.insertOne(new Document("name", "prometheus").append("reduce", true).append("license", "apache").append( + "value", + 100 + )) + tools.insertOne(new Document("name", "linux").append("reduce", true).append("license", "gpl").append( + "value", + 100 + )) tools.mapReduce( """ @@ -240,7 +252,6 @@ class MongoSyncDriverInstrumentationSpec extends EmbeddedMongoTest(port = 4445) | } |} """.stripMargin, - """ |function(key, values) { | return Array.sum(values) diff --git a/instrumentation/kamon-mongo/src/main/scala/kamon/instrumentation/mongo/MongoClientInstrumentation.scala b/instrumentation/kamon-mongo/src/main/scala/kamon/instrumentation/mongo/MongoClientInstrumentation.scala index 133ddee19..c9834d186 100644 --- a/instrumentation/kamon-mongo/src/main/scala/kamon/instrumentation/mongo/MongoClientInstrumentation.scala +++ b/instrumentation/kamon-mongo/src/main/scala/kamon/instrumentation/mongo/MongoClientInstrumentation.scala @@ -94,7 +94,6 @@ class MongoClientInstrumentation extends InstrumentationBuilder { } - class CopyOperationNameIntoMixedBulkWriteOperation object CopyOperationNameIntoMixedBulkWriteOperation { @@ -103,7 +102,7 @@ object CopyOperationNameIntoMixedBulkWriteOperation { def exit(@Advice.Return writeOperation: Any, @Advice.Origin("#m") methodName: String): Unit = { writeOperation match { case hon: HasOperationName => hon.setName(methodName) - case _ => + case _ => } } } diff --git a/instrumentation/kamon-mongo/src/test/scala/kamon/instrumentation/mongo/EmbeddedMongoTest.scala b/instrumentation/kamon-mongo/src/test/scala/kamon/instrumentation/mongo/EmbeddedMongoTest.scala index 391e72259..45f803824 100644 --- a/instrumentation/kamon-mongo/src/test/scala/kamon/instrumentation/mongo/EmbeddedMongoTest.scala +++ b/instrumentation/kamon-mongo/src/test/scala/kamon/instrumentation/mongo/EmbeddedMongoTest.scala @@ -46,5 +46,4 @@ abstract class EmbeddedMongoTest(port: Int) extends AnyWordSpec with Matchers wi super.afterAll() } - } diff --git a/instrumentation/kamon-mongo/src/test/scala/kamon/instrumentation/mongo/MongoScalaDriverInstrumentationSpec.scala b/instrumentation/kamon-mongo/src/test/scala/kamon/instrumentation/mongo/MongoScalaDriverInstrumentationSpec.scala index e188da095..c09c3b153 100644 --- a/instrumentation/kamon-mongo/src/test/scala/kamon/instrumentation/mongo/MongoScalaDriverInstrumentationSpec.scala +++ b/instrumentation/kamon-mongo/src/test/scala/kamon/instrumentation/mongo/MongoScalaDriverInstrumentationSpec.scala @@ -216,7 +216,9 @@ class MongoScalaDriverInstrumentationSpec extends EmbeddedMongoTest(port = 4445) tools.insertOne(Document("name" -> "kamon", "reduce" -> true, "license" -> "apache", "value" -> 100)).consume() tools.insertOne(Document("name" -> "zipkin", "reduce" -> true, "license" -> "apache", "value" -> 100)).consume() - tools.insertOne(Document("name" -> "prometheus", "reduce" -> true, "license" -> "apache", "value" -> 100)).consume() + tools.insertOne( + Document("name" -> "prometheus", "reduce" -> true, "license" -> "apache", "value" -> 100) + ).consume() tools.insertOne(Document("name" -> "linux", "reduce" -> true, "license" -> "gpl", "value" -> 100)).consume() tools.mapReduce( @@ -229,7 +231,6 @@ class MongoScalaDriverInstrumentationSpec extends EmbeddedMongoTest(port = 4445) | } |} """.stripMargin, - """ |function(key, values) { | return Array.sum(values) @@ -253,7 +254,9 @@ class MongoScalaDriverInstrumentationSpec extends EmbeddedMongoTest(port = 4445) tools.insertOne(Document("name" -> "kamon", "reduce" -> true, "license" -> "apache", "value" -> 100)).consume() tools.insertOne(Document("name" -> "zipkin", "reduce" -> true, "license" -> "apache", "value" -> 100)).consume() - tools.insertOne(Document("name" -> "prometheus", "reduce" -> true, "license" -> "apache", "value" -> 100)).consume() + tools.insertOne( + Document("name" -> "prometheus", "reduce" -> true, "license" -> "apache", "value" -> 100) + ).consume() tools.insertOne(Document("name" -> "linux", "reduce" -> true, "license" -> "gpl", "value" -> 100)).consume() tools.mapReduce( @@ -266,7 +269,6 @@ class MongoScalaDriverInstrumentationSpec extends EmbeddedMongoTest(port = 4445) | } |} """.stripMargin, - """ |function(key, values) { | return Array.sum(values) @@ -336,10 +338,8 @@ class MongoScalaDriverInstrumentationSpec extends EmbeddedMongoTest(port = 4445) } } - } - implicit class RichSingleObservable[T](observable: Observable[T]) { // Shorthand for just consuming results from an observable. diff --git a/instrumentation/kamon-mongo/src/test/scala/kamon/instrumentation/mongo/MongoSyncDriverInstrumentationSpec.scala b/instrumentation/kamon-mongo/src/test/scala/kamon/instrumentation/mongo/MongoSyncDriverInstrumentationSpec.scala index 1e403c486..63cd36fbe 100644 --- a/instrumentation/kamon-mongo/src/test/scala/kamon/instrumentation/mongo/MongoSyncDriverInstrumentationSpec.scala +++ b/instrumentation/kamon-mongo/src/test/scala/kamon/instrumentation/mongo/MongoSyncDriverInstrumentationSpec.scala @@ -38,7 +38,7 @@ class MongoSyncDriverInstrumentationSpec extends EmbeddedMongoTest(port = 4445) span } - while(aggregateResults.hasNext) { + while (aggregateResults.hasNext) { aggregateResults.next() } @@ -135,7 +135,7 @@ class MongoSyncDriverInstrumentationSpec extends EmbeddedMongoTest(port = 4445) } // We are exhausting the iterator to for the getMore operation to happen - while(results.hasNext) { + while (results.hasNext) { results.next() } @@ -225,10 +225,22 @@ class MongoSyncDriverInstrumentationSpec extends EmbeddedMongoTest(port = 4445) // fetching all the results from Mongo. If that behavior changes we should make sure that any getMore // operations are covered by this test. - tools.insertOne(new Document("name", "kamon").append("reduce", true).append("license", "apache").append("value", 100)) - tools.insertOne(new Document("name", "zipkin").append("reduce", true).append("license", "apache").append("value", 100)) - tools.insertOne(new Document("name", "prometheus").append("reduce", true).append("license", "apache").append("value", 100)) - tools.insertOne(new Document("name", "linux").append("reduce", true).append("license", "gpl").append("value", 100)) + tools.insertOne(new Document("name", "kamon").append("reduce", true).append("license", "apache").append( + "value", + 100 + )) + tools.insertOne(new Document("name", "zipkin").append("reduce", true).append("license", "apache").append( + "value", + 100 + )) + tools.insertOne(new Document("name", "prometheus").append("reduce", true).append("license", "apache").append( + "value", + 100 + )) + tools.insertOne(new Document("name", "linux").append("reduce", true).append("license", "gpl").append( + "value", + 100 + )) tools.mapReduce( """ @@ -240,7 +252,6 @@ class MongoSyncDriverInstrumentationSpec extends EmbeddedMongoTest(port = 4445) | } |} """.stripMargin, - """ |function(key, values) { | return Array.sum(values) diff --git a/instrumentation/kamon-okhttp/src/main/scala/kamon/okhttp3/instrumentation/KamonOkHttpTracing.scala b/instrumentation/kamon-okhttp/src/main/scala/kamon/okhttp3/instrumentation/KamonOkHttpTracing.scala index de8fae121..4740bdb01 100644 --- a/instrumentation/kamon-okhttp/src/main/scala/kamon/okhttp3/instrumentation/KamonOkHttpTracing.scala +++ b/instrumentation/kamon-okhttp/src/main/scala/kamon/okhttp3/instrumentation/KamonOkHttpTracing.scala @@ -34,7 +34,10 @@ object KamonOkHttpTracing { instrumentation.createHandler(getRequestBuilder(request), Kamon.currentContext) } - def successContinuation(requestHandler: HttpClientInstrumentation.RequestHandler[Request], response: Response): Response = { + def successContinuation( + requestHandler: HttpClientInstrumentation.RequestHandler[Request], + response: Response + ): Response = { requestHandler.processResponse(toKamonResponse(response)) response } @@ -44,39 +47,40 @@ object KamonOkHttpTracing { requestHandler.span.finish() } - def getRequestBuilder(request: Request): HttpMessage.RequestBuilder[Request] = new HttpMessage.RequestBuilder[Request]() { - private val _headers = mutable.Map[String, String]() + def getRequestBuilder(request: Request): HttpMessage.RequestBuilder[Request] = + new HttpMessage.RequestBuilder[Request]() { + private val _headers = mutable.Map[String, String]() - override def read(header: String): Option[String] = Option.apply(request.header(header)) + override def read(header: String): Option[String] = Option.apply(request.header(header)) - override def readAll: Map[String, String] = { - JavaConverters - .mapAsScalaMapConverter(request.headers.toMultimap) - .asScala - .mapValues((values: util.List[String]) => values.get(0)) - .toMap - } + override def readAll: Map[String, String] = { + JavaConverters + .mapAsScalaMapConverter(request.headers.toMultimap) + .asScala + .mapValues((values: util.List[String]) => values.get(0)) + .toMap + } - override def url: String = request.url.toString + override def url: String = request.url.toString - override def path: String = request.url.uri.getPath + override def path: String = request.url.uri.getPath - override def method: String = request.method + override def method: String = request.method - override def host: String = request.url.host + override def host: String = request.url.host - override def port: Int = request.url.port + override def port: Int = request.url.port - override def write(header: String, value: String): Unit = { - _headers += (header -> value) - } + override def write(header: String, value: String): Unit = { + _headers += (header -> value) + } - override def build: Request = { - val newHeadersMap = request.headers.newBuilder - _headers.foreach { case (key, value) => newHeadersMap.add(key, value) } - request.newBuilder.headers(newHeadersMap.build).build + override def build: Request = { + val newHeadersMap = request.headers.newBuilder + _headers.foreach { case (key, value) => newHeadersMap.add(key, value) } + request.newBuilder.headers(newHeadersMap.build).build + } } - } def toKamonResponse(response: Response): HttpMessage.Response = new HttpMessage.Response() { override def statusCode: Int = response.code() diff --git a/instrumentation/kamon-okhttp/src/test/scala/kamon/okhttp3/instrumentation/OkHttpTracingInstrumentationSpec.scala b/instrumentation/kamon-okhttp/src/test/scala/kamon/okhttp3/instrumentation/OkHttpTracingInstrumentationSpec.scala index be5b29ff8..e65a0ab2c 100644 --- a/instrumentation/kamon-okhttp/src/test/scala/kamon/okhttp3/instrumentation/OkHttpTracingInstrumentationSpec.scala +++ b/instrumentation/kamon-okhttp/src/test/scala/kamon/okhttp3/instrumentation/OkHttpTracingInstrumentationSpec.scala @@ -33,14 +33,14 @@ import org.scalatest.wordspec.AnyWordSpec import org.scalatest.{BeforeAndAfterEach, OptionValues} class OkHttpTracingInstrumentationSpec extends AnyWordSpec - with Matchers - with Eventually - with SpanSugar - with BeforeAndAfterEach - with TestSpanReporter - with JettySupport - with Reconfigure - with OptionValues { + with Matchers + with Eventually + with SpanSugar + with BeforeAndAfterEach + with TestSpanReporter + with JettySupport + with Reconfigure + with OptionValues { val customTag = "requestId" val customHeaderName = "X-Request-Id" @@ -274,7 +274,7 @@ class OkHttpTracingInstrumentationSpec extends AnyWordSpec req.getRequestURI match { case path if path == uriError => resp.setStatus(500) - case _ => resp.setStatus(200) + case _ => resp.setStatus(200) } } } @@ -292,7 +292,8 @@ class OkHttpTracingInstrumentationSpec extends AnyWordSpec | $customTag = span | } |} - |""".stripMargin) + |""".stripMargin + ) startServer() } diff --git a/instrumentation/kamon-opensearch/src/main/scala/kamon/instrumentation/opensearch/OSInstrumentation.scala b/instrumentation/kamon-opensearch/src/main/scala/kamon/instrumentation/opensearch/OSInstrumentation.scala index b8f762e7f..08aebb1e4 100644 --- a/instrumentation/kamon-opensearch/src/main/scala/kamon/instrumentation/opensearch/OSInstrumentation.scala +++ b/instrumentation/kamon-opensearch/src/main/scala/kamon/instrumentation/opensearch/OSInstrumentation.scala @@ -29,7 +29,10 @@ class OSInstrumentation extends InstrumentationBuilder { onType("org.opensearch.client.RestHighLevelClient") .advise(method("internalPerformRequest").and(takesArguments(5)), classOf[HighLevelOpensearchClientInstrumentation]) - .advise(method("internalPerformRequestAsync").and(takesArguments(6)), classOf[HighLevelOpensearchClientInstrumentation]) + .advise( + method("internalPerformRequestAsync").and(takesArguments(6)), + classOf[HighLevelOpensearchClientInstrumentation] + ) } class InstrumentedListener(inner: ResponseListener, span: Span) extends ResponseListener { diff --git a/instrumentation/kamon-opensearch/src/test/scala/kamon/instrumentation/OpenSearchInstrumentationTest.scala b/instrumentation/kamon-opensearch/src/test/scala/kamon/instrumentation/OpenSearchInstrumentationTest.scala index 67a0ecd09..36bb96f96 100644 --- a/instrumentation/kamon-opensearch/src/test/scala/kamon/instrumentation/OpenSearchInstrumentationTest.scala +++ b/instrumentation/kamon-opensearch/src/test/scala/kamon/instrumentation/OpenSearchInstrumentationTest.scala @@ -14,9 +14,8 @@ import org.scalatest.wordspec.AnyWordSpec import org.scalatest.OptionValues import org.testcontainers.containers.wait.strategy.Wait - class OpenSearchInstrumentationTest - extends AnyWordSpec + extends AnyWordSpec with Matchers with Eventually with SpanSugar @@ -42,11 +41,13 @@ class OpenSearchInstrumentationTest } "records a span for a basic async request" in { - client.performRequestAsync(new Request("GET", "/_cluster/health"), + client.performRequestAsync( + new Request("GET", "/_cluster/health"), new ResponseListener() { override def onSuccess(response: Response): Unit = () override def onFailure(exception: Exception): Unit = () - }) + } + ) eventually(timeout(5 seconds)) { val span = testSpanReporter().nextSpan().value @@ -85,7 +86,6 @@ class OpenSearchInstrumentationTest } } - override val container: GenericContainer = GenericContainer( "opensearchproject/opensearch:1.3.14", exposedPorts = Seq(9200), @@ -104,7 +104,8 @@ class OpenSearchInstrumentationTest .build() highLevelClient = new RestHighLevelClient( - RestClient.builder(HttpHost.create(s"${container.host}:${container.mappedPort(9200)}"))) + RestClient.builder(HttpHost.create(s"${container.host}:${container.mappedPort(9200)}")) + ) } override protected def afterAll(): Unit = { diff --git a/instrumentation/kamon-pekko-grpc/src/main/scala/kamon/instrumentation/pekko/grpc/PekkoGrpcServerInstrumentation.scala b/instrumentation/kamon-pekko-grpc/src/main/scala/kamon/instrumentation/pekko/grpc/PekkoGrpcServerInstrumentation.scala index 61ae73d9c..4d788281f 100644 --- a/instrumentation/kamon-pekko-grpc/src/main/scala/kamon/instrumentation/pekko/grpc/PekkoGrpcServerInstrumentation.scala +++ b/instrumentation/kamon-pekko-grpc/src/main/scala/kamon/instrumentation/pekko/grpc/PekkoGrpcServerInstrumentation.scala @@ -38,7 +38,6 @@ class PekkoGrpcServerInstrumentation extends InstrumentationBuilder { onType("org.apache.pekko.grpc.internal.TelemetrySpi") .advise(method("onRequest"), classOf[PekkoGRPCServerRequestHandler]) - onType("org.apache.pekko.grpc.scaladsl.GrpcMarshalling") .advise(method("unmarshal"), classOf[PekkoGRPCUnmarshallingContextPropagation]) } diff --git a/instrumentation/kamon-pekko-grpc/src/test/scala/kamon/instrumentation/pekko/grpc/GreeterServiceImpl.scala b/instrumentation/kamon-pekko-grpc/src/test/scala/kamon/instrumentation/pekko/grpc/GreeterServiceImpl.scala index 1b59ca4b5..465ceb3c1 100644 --- a/instrumentation/kamon-pekko-grpc/src/test/scala/kamon/instrumentation/pekko/grpc/GreeterServiceImpl.scala +++ b/instrumentation/kamon-pekko-grpc/src/test/scala/kamon/instrumentation/pekko/grpc/GreeterServiceImpl.scala @@ -22,7 +22,6 @@ import org.apache.pekko.stream.Materializer import org.apache.pekko.stream.scaladsl.Sink import org.apache.pekko.stream.scaladsl.Source - class GreeterServiceImpl(implicit mat: Materializer) extends GreeterService { import mat.executionContext diff --git a/instrumentation/kamon-pekko-grpc/src/test/scala/kamon/instrumentation/pekko/grpc/PekkoGrpcTracingSpec.scala b/instrumentation/kamon-pekko-grpc/src/test/scala/kamon/instrumentation/pekko/grpc/PekkoGrpcTracingSpec.scala index b09c69f72..5dd91a8dc 100644 --- a/instrumentation/kamon-pekko-grpc/src/test/scala/kamon/instrumentation/pekko/grpc/PekkoGrpcTracingSpec.scala +++ b/instrumentation/kamon-pekko-grpc/src/test/scala/kamon/instrumentation/pekko/grpc/PekkoGrpcTracingSpec.scala @@ -40,7 +40,6 @@ class PekkoGrpcTracingSpec extends AnyWordSpec with InitAndStopKamonAfterAll wit .newServerAt("127.0.0.1", 8598) .bind(greeterService) - val client = GreeterServiceClient(GrpcClientSettings.connectToServiceAt("127.0.0.1", 8598).withTls(false)) "the Pekko gRPC instrumentation" should { diff --git a/instrumentation/kamon-pekko-http/src/main/scala/kamon/instrumentation/pekko/http/PekkoHttpClientInstrumentation.scala b/instrumentation/kamon-pekko-http/src/main/scala/kamon/instrumentation/pekko/http/PekkoHttpClientInstrumentation.scala index 702091d28..64741d909 100644 --- a/instrumentation/kamon-pekko-http/src/main/scala/kamon/instrumentation/pekko/http/PekkoHttpClientInstrumentation.scala +++ b/instrumentation/kamon-pekko-http/src/main/scala/kamon/instrumentation/pekko/http/PekkoHttpClientInstrumentation.scala @@ -40,18 +40,21 @@ class PekkoHttpClientInstrumentation extends InstrumentationBuilder { object PekkoHttpClientInstrumentation { - @volatile var httpClientInstrumentation: HttpClientInstrumentation = rebuildHttpClientInstrumentation + @volatile var httpClientInstrumentation: HttpClientInstrumentation = rebuildHttpClientInstrumentation - private[http] def rebuildHttpClientInstrumentation(): HttpClientInstrumentation = { - val httpClientConfig = Kamon.config().getConfig("kamon.instrumentation.pekko.http.client") - httpClientInstrumentation = HttpClientInstrumentation.from(httpClientConfig, "pekko.http.client") - httpClientInstrumentation - } + private[http] def rebuildHttpClientInstrumentation(): HttpClientInstrumentation = { + val httpClientConfig = Kamon.config().getConfig("kamon.instrumentation.pekko.http.client") + httpClientInstrumentation = HttpClientInstrumentation.from(httpClientConfig, "pekko.http.client") + httpClientInstrumentation + } - def handleResponse(responseFuture: Future[HttpResponse], handler: RequestHandler[HttpRequest]): Future[HttpResponse] = { + def handleResponse( + responseFuture: Future[HttpResponse], + handler: RequestHandler[HttpRequest] + ): Future[HttpResponse] = { responseFuture.onComplete { case Success(response) => handler.processResponse(toResponse(response)) - case Failure(t) => handler.span.fail(t).finish() + case Failure(t) => handler.span.fail(t).finish() }(CallingThreadExecutionContext) responseFuture diff --git a/instrumentation/kamon-pekko-http/src/main/scala/kamon/instrumentation/pekko/http/PekkoHttpInstrumentation.scala b/instrumentation/kamon-pekko-http/src/main/scala/kamon/instrumentation/pekko/http/PekkoHttpInstrumentation.scala index b13de4509..1975c3f50 100644 --- a/instrumentation/kamon-pekko-http/src/main/scala/kamon/instrumentation/pekko/http/PekkoHttpInstrumentation.scala +++ b/instrumentation/kamon-pekko-http/src/main/scala/kamon/instrumentation/pekko/http/PekkoHttpInstrumentation.scala @@ -45,18 +45,19 @@ object PekkoHttpInstrumentation { request.withHeaders(request.headers ++ _extraHeaders) } - def toResponseBuilder(response: HttpResponse): HttpMessage.ResponseBuilder[HttpResponse] = new HttpMessage.ResponseBuilder[HttpResponse] { - private var _headers = response.headers + def toResponseBuilder(response: HttpResponse): HttpMessage.ResponseBuilder[HttpResponse] = + new HttpMessage.ResponseBuilder[HttpResponse] { + private var _headers = response.headers - override def statusCode: Int = - response.status.intValue() + override def statusCode: Int = + response.status.intValue() - override def write(header: String, value: String): Unit = - _headers = RawHeader(header, value) +: _headers + override def write(header: String, value: String): Unit = + _headers = RawHeader(header, value) +: _headers - override def build(): HttpResponse = - response.withHeaders(_headers) - } + override def build(): HttpResponse = + response.withHeaders(_headers) + } /** * Bundles together the read parts of the HTTP Request mapping @@ -81,7 +82,7 @@ object PekkoHttpInstrumentation { override def read(header: String): Option[String] = { val headerValue = request.getHeader(header) - if(headerValue.isPresent) + if (headerValue.isPresent) Some(headerValue.get().value()) else None } diff --git a/instrumentation/kamon-pekko-http/src/main/scala/kamon/instrumentation/pekko/http/PekkoHttpServerInstrumentation.scala b/instrumentation/kamon-pekko-http/src/main/scala/kamon/instrumentation/pekko/http/PekkoHttpServerInstrumentation.scala index 561909a4c..473184aa2 100644 --- a/instrumentation/kamon-pekko-http/src/main/scala/kamon/instrumentation/pekko/http/PekkoHttpServerInstrumentation.scala +++ b/instrumentation/kamon-pekko-http/src/main/scala/kamon/instrumentation/pekko/http/PekkoHttpServerInstrumentation.scala @@ -25,8 +25,8 @@ import scala.collection.immutable import scala.concurrent.Future import scala.util.{Failure, Success, Try} - class PekkoHttpServerInstrumentation extends InstrumentationBuilder { + /** * When instrumenting bindAndHandle what we do is wrap the Flow[HttpRequest, HttpResponse, NotUsed] provided by * the user and add all the processing there. This is the part of the instrumentation that performs Context @@ -65,7 +65,10 @@ class PekkoHttpServerInstrumentation extends InstrumentationBuilder { onType("org.apache.pekko.http.scaladsl.server.directives.FutureDirectives") .intercept(method("onComplete"), classOf[ResolveOperationNameOnRouteInterceptor]) - onTypes("org.apache.pekko.http.scaladsl.server.directives.OnSuccessMagnet$", "org.apache.pekko.http.scaladsl.server.directives.CompleteOrRecoverWithMagnet$") + onTypes( + "org.apache.pekko.http.scaladsl.server.directives.OnSuccessMagnet$", + "org.apache.pekko.http.scaladsl.server.directives.CompleteOrRecoverWithMagnet$" + ) .intercept(method("apply"), classOf[ResolveOperationNameOnRouteInterceptor]) onType("org.apache.pekko.http.scaladsl.server.directives.RouteDirectives") @@ -73,7 +76,6 @@ class PekkoHttpServerInstrumentation extends InstrumentationBuilder { .intercept(method("redirect"), classOf[ResolveOperationNameOnRouteInterceptor]) .intercept(method("failWith"), classOf[ResolveOperationNameOnRouteInterceptor]) - /** * Support for HTTP/1 and HTTP/2 at the same time. * @@ -94,12 +96,13 @@ trait HasMatchingContext { object HasMatchingContext { - case class PathMatchingContext ( + case class PathMatchingContext( fullPath: String, matched: Matched[_] ) - class Mixin(var matchingContext: Seq[PathMatchingContext], var defaultOperationName: String) extends HasMatchingContext { + class Mixin(var matchingContext: Seq[PathMatchingContext], var defaultOperationName: String) + extends HasMatchingContext { override def setMatchingContext(matchingContext: Seq[PathMatchingContext]): Unit = this.matchingContext = matchingContext @@ -133,7 +136,9 @@ object ResolveOperationNameOnRouteInterceptor { def complete[T](status: StatusCode, v: => T)(implicit m: ToEntityMarshaller[T]): StandardRoute = StandardRoute(resolveOperationName(_).complete((status, v))) - def complete[T](status: StatusCode, headers: immutable.Seq[HttpHeader], v: => T)(implicit m: ToEntityMarshaller[T]): StandardRoute = + def complete[T](status: StatusCode, headers: immutable.Seq[HttpHeader], v: => T)(implicit + m: ToEntityMarshaller[T] + ): StandardRoute = complete((status, headers, v)) def redirect(uri: Uri, redirectionType: Redirection): StandardRoute = @@ -182,8 +187,8 @@ object ResolveOperationNameOnRouteInterceptor { Kamon.currentContext().get(LastAutomaticOperationNameEdit.Key).foreach(lastEdit => { val currentSpan = Kamon.currentSpan() - if(lastEdit.allowAutomaticChanges) { - if(currentSpan.operationName() == lastEdit.operationName) { + if (lastEdit.allowAutomaticChanges) { + if (currentSpan.operationName() == lastEdit.operationName) { val allMatches = requestContext.asInstanceOf[HasMatchingContext].matchingContext.reverse.map(singleMatch) val operationName = allMatches.mkString("") @@ -211,7 +216,7 @@ object ResolveOperationNameOnRouteInterceptor { val consumedSegment = matching.fullPath.substring(0, consumedCount) matching.matched.extractions match { - case () => //string segment matched + case () => // string segment matched consumedSegment case tuple: Product => val values = tuple.productIterator.toList map { @@ -257,7 +262,9 @@ object RequestContextCopyInterceptor { @RuntimeType def copy(@This context: RequestContext, @SuperCall copyCall: Callable[RequestContext]): RequestContext = { val copiedRequestContext = copyCall.call() - copiedRequestContext.asInstanceOf[HasMatchingContext].setMatchingContext(context.asInstanceOf[HasMatchingContext].matchingContext) + copiedRequestContext.asInstanceOf[HasMatchingContext].setMatchingContext( + context.asInstanceOf[HasMatchingContext].matchingContext + ) copiedRequestContext } } @@ -284,8 +291,7 @@ object PathDirectivesRawPathPrefixInterceptor { } flatMap { case (ctx, Matched(rest, values)) => tprovide[T](values) & mapRequestContext(_ withUnmatchedPath rest) & mapRouteResult { routeResult => - - if(routeResult.isInstanceOf[Rejected]) + if (routeResult.isInstanceOf[Rejected]) ctx.asInstanceOf[HasMatchingContext].popOneMatchingContext() routeResult @@ -305,8 +311,10 @@ object Http2BlueprintInterceptor { } @RuntimeType - def handleWithStreamIdHeader(@Argument(1) handler: HttpRequest => Future[HttpResponse], - @SuperCall zuper: Callable[Flow[HttpRequest, HttpResponse, NotUsed]]): Flow[HttpRequest, HttpResponse, NotUsed] = { + def handleWithStreamIdHeader( + @Argument(1) handler: HttpRequest => Future[HttpResponse], + @SuperCall zuper: Callable[Flow[HttpRequest, HttpResponse, NotUsed]] + ): Flow[HttpRequest, HttpResponse, NotUsed] = { handler match { case HandlerWithEndpoint(interface, port, _) => diff --git a/instrumentation/kamon-pekko-http/src/main/scala/kamon/instrumentation/pekko/http/ServerFlowWrapper.scala b/instrumentation/kamon-pekko-http/src/main/scala/kamon/instrumentation/pekko/http/ServerFlowWrapper.scala index d555abe8a..98e7e1532 100644 --- a/instrumentation/kamon-pekko-http/src/main/scala/kamon/instrumentation/pekko/http/ServerFlowWrapper.scala +++ b/instrumentation/kamon-pekko-http/src/main/scala/kamon/instrumentation/pekko/http/ServerFlowWrapper.scala @@ -50,146 +50,169 @@ object ServerFlowWrapper { private val _defaultSettings = Settings("pekko.http.server", "kamon.instrumentation.pekko.http.server") @volatile private var _wrapperSettings = _defaultSettings - def apply(flow: Flow[HttpRequest, HttpResponse, NotUsed], interface: String, port: Int): Flow[HttpRequest, HttpResponse, NotUsed] = + def apply( + flow: Flow[HttpRequest, HttpResponse, NotUsed], + interface: String, + port: Int + ): Flow[HttpRequest, HttpResponse, NotUsed] = BidiFlow.fromGraph(wrapStage(_wrapperSettings, interface, port)).join(flow) - def wrapStage(settings: Settings, interface: String, port: Int) = new GraphStage[BidiShape[HttpRequest, HttpRequest, HttpResponse, HttpResponse]] { - val httpServerConfig = Kamon.config().getConfig(settings.configPath) - val httpServerInstrumentation = HttpServerInstrumentation.from(httpServerConfig, settings.component, interface, port) - val requestIn = Inlet.create[HttpRequest]("request.in") - val requestOut = Outlet.create[HttpRequest]("request.out") - val responseIn = Inlet.create[HttpResponse]("response.in") - val responseOut = Outlet.create[HttpResponse]("response.out") - - override val shape = BidiShape(requestIn, requestOut, responseIn, responseOut) - - override def createLogic(inheritedAttributes: Attributes) = new GraphStageLogic(shape) { - - // There might be more than one outstanding request when HTTP pipelining is enabled but according to the Akka HTTP - // documentation, it is required by the applications to generate responses for all requests and to generate them - // in the appropriate order, so we can simply queue and dequeue the RequestHandlers as the requests flow through - // the Stage. - // - // More info: https://doc.akka.io/docs/akka-http/current/server-side/low-level-api.html#request-response-cycle - private val _pendingRequests = mutable.Queue.empty[RequestHandler] - private val _createdAt = Kamon.clock().instant() - private var _completedRequests = 0 - - setHandler(requestIn, new InHandler { - override def onPush(): Unit = { - val request = grab(requestIn) - val requestHandler = httpServerInstrumentation.createHandler(toRequest(request), deferSamplingDecision = true) - .requestReceived() - - val defaultOperationName = httpServerInstrumentation.settings.defaultOperationName - val requestSpan = requestHandler.span - - // Automatic Operation name changes will only be allowed if the initial name HTTP Server didn't assign a - // user-defined name to the operation (that would be, either via an Operation Name Generator or a custom - // operation mapping). - val allowAutomaticChanges = requestSpan.operationName() == defaultOperationName - - _pendingRequests.enqueue(requestHandler) - - // The only reason why it's safe to leave the Thread dirty is because the Actor - // instrumentation will cleanup afterwards. - Kamon.storeContext(requestHandler.context.withEntry( - LastAutomaticOperationNameEdit.Key, Option(LastAutomaticOperationNameEdit(requestSpan.operationName(), allowAutomaticChanges)) - )) - - push(requestOut, request) - } + def wrapStage(settings: Settings, interface: String, port: Int) = + new GraphStage[BidiShape[HttpRequest, HttpRequest, HttpResponse, HttpResponse]] { + val httpServerConfig = Kamon.config().getConfig(settings.configPath) + val httpServerInstrumentation = + HttpServerInstrumentation.from(httpServerConfig, settings.component, interface, port) + val requestIn = Inlet.create[HttpRequest]("request.in") + val requestOut = Outlet.create[HttpRequest]("request.out") + val responseIn = Inlet.create[HttpResponse]("response.in") + val responseOut = Outlet.create[HttpResponse]("response.out") + + override val shape = BidiShape(requestIn, requestOut, responseIn, responseOut) + + override def createLogic(inheritedAttributes: Attributes) = new GraphStageLogic(shape) { + + // There might be more than one outstanding request when HTTP pipelining is enabled but according to the Akka HTTP + // documentation, it is required by the applications to generate responses for all requests and to generate them + // in the appropriate order, so we can simply queue and dequeue the RequestHandlers as the requests flow through + // the Stage. + // + // More info: https://doc.akka.io/docs/akka-http/current/server-side/low-level-api.html#request-response-cycle + private val _pendingRequests = mutable.Queue.empty[RequestHandler] + private val _createdAt = Kamon.clock().instant() + private var _completedRequests = 0 + + setHandler( + requestIn, + new InHandler { + override def onPush(): Unit = { + val request = grab(requestIn) + val requestHandler = + httpServerInstrumentation.createHandler(toRequest(request), deferSamplingDecision = true) + .requestReceived() + + val defaultOperationName = httpServerInstrumentation.settings.defaultOperationName + val requestSpan = requestHandler.span + + // Automatic Operation name changes will only be allowed if the initial name HTTP Server didn't assign a + // user-defined name to the operation (that would be, either via an Operation Name Generator or a custom + // operation mapping). + val allowAutomaticChanges = requestSpan.operationName() == defaultOperationName + + _pendingRequests.enqueue(requestHandler) + + // The only reason why it's safe to leave the Thread dirty is because the Actor + // instrumentation will cleanup afterwards. + Kamon.storeContext(requestHandler.context.withEntry( + LastAutomaticOperationNameEdit.Key, + Option(LastAutomaticOperationNameEdit(requestSpan.operationName(), allowAutomaticChanges)) + )) + + push(requestOut, request) + } - override def onUpstreamFinish(): Unit = - complete(requestOut) - }) - - setHandler(requestOut, new OutHandler { - override def onPull(): Unit = - pull(requestIn) - - override def onDownstreamFinish(t: Throwable): Unit = - cancel(requestIn, t) - }) - - setHandler(responseIn, new InHandler { - override def onPush(): Unit = { - val response = grab(responseIn) - val requestHandler = _pendingRequests.dequeue() - val requestSpan = requestHandler.span - val responseWithContext = requestHandler.buildResponse(toResponseBuilder(response), requestHandler.context) - - if(response.status.intValue() == 404 && requestSpan.operationName() == httpServerInstrumentation.settings.defaultOperationName) { - - // It might happen that if no route was able to handle the request or no directive that would force taking - // a sampling decision was run, the request would still not have any sampling decision so we both set the - // request as unhandled and take a sampling decision for that operation here. - requestSpan - .name(httpServerInstrumentation.settings.unhandledOperationName) - .takeSamplingDecision() + override def onUpstreamFinish(): Unit = + complete(requestOut) } + ) - val entity = if(responseWithContext.entity.isKnownEmpty()) { - requestHandler.responseSent(0L) - responseWithContext.entity - } else { - - requestSpan.mark("http.response.ready") - - responseWithContext.entity match { - case strict @ HttpEntity.Strict(_, bs) => - requestHandler.responseSent(bs.size) - strict - - case default: HttpEntity.Default => - requestHandler.responseSent(default.contentLength) - default - - case _ => - val responseSizeCounter = new AtomicLong(0L) - responseWithContext.entity.transformDataBytes( - Flow[ByteString] - .watchTermination()(Keep.right) - .wireTap(bs => responseSizeCounter.addAndGet(bs.size)) - .mapMaterializedValue { f => - f.andThen { - case Success(_) => - requestHandler.responseSent(responseSizeCounter.get()) - case Failure(e) => - requestSpan.fail("Response entity stream failed", e) - requestHandler.responseSent(responseSizeCounter.get()) - - }(CallingThreadExecutionContext) - } - ) - } - } + setHandler( + requestOut, + new OutHandler { + override def onPull(): Unit = + pull(requestIn) - _completedRequests += 1 - push(responseOut, responseWithContext.withEntity(entity)) - } + override def onDownstreamFinish(t: Throwable): Unit = + cancel(requestIn, t) + } + ) + + setHandler( + responseIn, + new InHandler { + override def onPush(): Unit = { + val response = grab(responseIn) + val requestHandler = _pendingRequests.dequeue() + val requestSpan = requestHandler.span + val responseWithContext = + requestHandler.buildResponse(toResponseBuilder(response), requestHandler.context) + + if ( + response.status.intValue() == 404 && requestSpan.operationName() == httpServerInstrumentation.settings.defaultOperationName + ) { + + // It might happen that if no route was able to handle the request or no directive that would force taking + // a sampling decision was run, the request would still not have any sampling decision so we both set the + // request as unhandled and take a sampling decision for that operation here. + requestSpan + .name(httpServerInstrumentation.settings.unhandledOperationName) + .takeSamplingDecision() + } + + val entity = if (responseWithContext.entity.isKnownEmpty()) { + requestHandler.responseSent(0L) + responseWithContext.entity + } else { + + requestSpan.mark("http.response.ready") + + responseWithContext.entity match { + case strict @ HttpEntity.Strict(_, bs) => + requestHandler.responseSent(bs.size) + strict + + case default: HttpEntity.Default => + requestHandler.responseSent(default.contentLength) + default + + case _ => + val responseSizeCounter = new AtomicLong(0L) + responseWithContext.entity.transformDataBytes( + Flow[ByteString] + .watchTermination()(Keep.right) + .wireTap(bs => responseSizeCounter.addAndGet(bs.size)) + .mapMaterializedValue { f => + f.andThen { + case Success(_) => + requestHandler.responseSent(responseSizeCounter.get()) + case Failure(e) => + requestSpan.fail("Response entity stream failed", e) + requestHandler.responseSent(responseSizeCounter.get()) + + }(CallingThreadExecutionContext) + } + ) + } + } + + _completedRequests += 1 + push(responseOut, responseWithContext.withEntity(entity)) + } - override def onUpstreamFinish(): Unit = - completeStage() - }) + override def onUpstreamFinish(): Unit = + completeStage() + } + ) - setHandler(responseOut, new OutHandler { - override def onPull(): Unit = - pull(responseIn) + setHandler( + responseOut, + new OutHandler { + override def onPull(): Unit = + pull(responseIn) - override def onDownstreamFinish(t: Throwable): Unit = - cancel(responseIn, t) - }) + override def onDownstreamFinish(t: Throwable): Unit = + cancel(responseIn, t) + } + ) - override def preStart(): Unit = - httpServerInstrumentation.connectionOpened() + override def preStart(): Unit = + httpServerInstrumentation.connectionOpened() - override def postStop(): Unit = { - val connectionLifetime = Duration.between(_createdAt, Kamon.clock().instant()) - httpServerInstrumentation.connectionClosed(connectionLifetime, _completedRequests) + override def postStop(): Unit = { + val connectionLifetime = Duration.between(_createdAt, Kamon.clock().instant()) + httpServerInstrumentation.connectionClosed(connectionLifetime, _completedRequests) + } } } - } def changeSettings(component: String, configPath: String): Unit = _wrapperSettings = Settings(component, configPath) @@ -198,9 +221,11 @@ object ServerFlowWrapper { _wrapperSettings = _defaultSettings def defaultOperationName(listenPort: Int): String = - _defaultOperationNames.getOrElseUpdate(listenPort, { - _serverInstrumentations.get(listenPort).map(_.settings.defaultOperationName).getOrElse("http.server.request") - }) + _defaultOperationNames.getOrElseUpdate( + listenPort, { + _serverInstrumentations.get(listenPort).map(_.settings.defaultOperationName).getOrElse("http.server.request") + } + ) case class Settings(component: String, configPath: String) } diff --git a/instrumentation/kamon-pekko-http/src/main/scala/kamon/instrumentation/pekko/http/TracingDirectives.scala b/instrumentation/kamon-pekko-http/src/main/scala/kamon/instrumentation/pekko/http/TracingDirectives.scala index ec2b4ceb8..0647d8b8e 100644 --- a/instrumentation/kamon-pekko-http/src/main/scala/kamon/instrumentation/pekko/http/TracingDirectives.scala +++ b/instrumentation/kamon-pekko-http/src/main/scala/kamon/instrumentation/pekko/http/TracingDirectives.scala @@ -20,7 +20,6 @@ import org.apache.pekko.http.scaladsl.server.Directive0 import org.apache.pekko.http.scaladsl.server.directives.BasicDirectives import kamon.Kamon - trait TracingDirectives extends BasicDirectives { /** @@ -31,7 +30,7 @@ trait TracingDirectives extends BasicDirectives { val operationSpan = Kamon.currentSpan() operationSpan.name(name) - if(takeSamplingDecision) + if (takeSamplingDecision) operationSpan.takeSamplingDecision() req diff --git a/instrumentation/kamon-pekko-http/src/test/scala/kamon/pekko/http/PekkoHttpClientTracingSpec.scala b/instrumentation/kamon-pekko-http/src/test/scala/kamon/pekko/http/PekkoHttpClientTracingSpec.scala index 7ff1f0c44..5a2727729 100644 --- a/instrumentation/kamon-pekko-http/src/test/scala/kamon/pekko/http/PekkoHttpClientTracingSpec.scala +++ b/instrumentation/kamon-pekko-http/src/test/scala/kamon/pekko/http/PekkoHttpClientTracingSpec.scala @@ -12,7 +12,7 @@ * either express or implied. See the License for the specific language governing permissions * and limitations under the License. * ========================================================================================= -*/ + */ package kamon.pekko.http @@ -34,7 +34,8 @@ import org.scalatest.wordspec.AnyWordSpecLike import scala.concurrent.ExecutionContextExecutor import scala.concurrent.duration._ -class PekkoHttpClientTracingSpec extends AnyWordSpecLike with Matchers with InitAndStopKamonAfterAll with MetricInspection.Syntax +class PekkoHttpClientTracingSpec extends AnyWordSpecLike with Matchers with InitAndStopKamonAfterAll + with MetricInspection.Syntax with Reconfigure with TestWebServer with Eventually with OptionValues with TestSpanReporter { import TestWebServer.Endpoints._ @@ -90,7 +91,7 @@ class PekkoHttpClientTracingSpec extends AnyWordSpecLike with Matchers with Init val httpResponse = response.value.value.get val headersMap = parse(httpResponse.data.utf8String).extract[Map[String, String]] - headersMap.keys.toList should contain allOf( + headersMap.keys.toList should contain allOf ( "context-tags", "X-Foo", "X-B3-TraceId", @@ -134,4 +135,3 @@ class PekkoHttpClientTracingSpec extends AnyWordSpecLike with Matchers with Init webServer.shutdown() } } - diff --git a/instrumentation/kamon-pekko-http/src/test/scala/kamon/pekko/http/PekkoHttpServerMetricsSpec.scala b/instrumentation/kamon-pekko-http/src/test/scala/kamon/pekko/http/PekkoHttpServerMetricsSpec.scala index 3e655015b..adf566891 100644 --- a/instrumentation/kamon-pekko-http/src/test/scala/kamon/pekko/http/PekkoHttpServerMetricsSpec.scala +++ b/instrumentation/kamon-pekko-http/src/test/scala/kamon/pekko/http/PekkoHttpServerMetricsSpec.scala @@ -12,7 +12,7 @@ * either express or implied. See the License for the specific language governing permissions * and limitations under the License. * ========================================================================================= -*/ + */ package kamon.pekko.http @@ -32,8 +32,9 @@ import org.scalatest.wordspec.AnyWordSpecLike import scala.concurrent.{ExecutionContextExecutor, Future} import scala.concurrent.duration._ -class PekkoHttpServerMetricsSpec extends AnyWordSpecLike with Matchers with InitAndStopKamonAfterAll with InstrumentInspection.Syntax - with Reconfigure with TestWebServer with Eventually with OptionValues { +class PekkoHttpServerMetricsSpec extends AnyWordSpecLike with Matchers with InitAndStopKamonAfterAll + with InstrumentInspection.Syntax + with Reconfigure with TestWebServer with Eventually with OptionValues { import TestWebServer.Endpoints._ @@ -50,18 +51,18 @@ class PekkoHttpServerMetricsSpec extends AnyWordSpecLike with Matchers with Init "track the number of open connections and active requests on the Server side" in { val httpServerMetrics = HttpServerMetrics.of("pekko.http.server", interface, port) - for(_ <- 1 to 8) yield { + for (_ <- 1 to 8) yield { sendRequest(HttpRequest(uri = s"http://$interface:$port/$waitTen")) } eventually(timeout(10 seconds)) { - httpServerMetrics.openConnections.distribution().max shouldBe(8) - httpServerMetrics.activeRequests.distribution().max shouldBe(8) + httpServerMetrics.openConnections.distribution().max shouldBe (8) + httpServerMetrics.activeRequests.distribution().max shouldBe (8) } eventually(timeout(20 seconds)) { - httpServerMetrics.openConnections.distribution().max shouldBe(0) - httpServerMetrics.activeRequests.distribution().max shouldBe(0) + httpServerMetrics.openConnections.distribution().max shouldBe (0) + httpServerMetrics.activeRequests.distribution().max shouldBe (0) } } } @@ -70,7 +71,7 @@ class PekkoHttpServerMetricsSpec extends AnyWordSpecLike with Matchers with Init val connectionSettings = ClientConnectionSettings(system).withIdleTimeout(1 second) Source.single(request) .via(Http().outgoingConnection(interface, port, settings = connectionSettings)) - .map{r => + .map { r => r.discardEntityBytes() r } @@ -82,4 +83,3 @@ class PekkoHttpServerMetricsSpec extends AnyWordSpecLike with Matchers with Init webServer.shutdown() } } - diff --git a/instrumentation/kamon-pekko-http/src/test/scala/kamon/pekko/http/PekkoHttpServerTracingSpec.scala b/instrumentation/kamon-pekko-http/src/test/scala/kamon/pekko/http/PekkoHttpServerTracingSpec.scala index 5da805ac1..0c69aa6cf 100644 --- a/instrumentation/kamon-pekko-http/src/test/scala/kamon/pekko/http/PekkoHttpServerTracingSpec.scala +++ b/instrumentation/kamon-pekko-http/src/test/scala/kamon/pekko/http/PekkoHttpServerTracingSpec.scala @@ -12,7 +12,7 @@ * either express or implied. See the License for the specific language governing permissions * and limitations under the License. * ========================================================================================= -*/ + */ package kamon.pekko.http @@ -33,8 +33,10 @@ import scala.collection.JavaConverters._ import scala.concurrent.ExecutionContext import scala.util.control.NonFatal -class PekkoHttpServerTracingSpec extends AnyWordSpecLike with Matchers with ScalaFutures with Inside with InitAndStopKamonAfterAll - with MetricInspection.Syntax with Reconfigure with TestWebServer with Eventually with OptionValues with TestSpanReporter { +class PekkoHttpServerTracingSpec extends AnyWordSpecLike with Matchers with ScalaFutures with Inside + with InitAndStopKamonAfterAll + with MetricInspection.Syntax with Reconfigure with TestWebServer with Eventually with OptionValues + with TestSpanReporter { import TestWebServer.Endpoints._ @@ -72,7 +74,6 @@ class PekkoHttpServerTracingSpec extends AnyWordSpecLike with Matchers with Scal val target = s"$protocol://$interface:$port/$dummyPathOk" client.newCall(new Request.Builder().url(target).build()).execute() - eventually(timeout(10 seconds)) { val span = testSpanReporter().nextSpan().value span.tags.get(plain("http.url")) should endWith(s"$interface:$port/$dummyPathOk") @@ -218,7 +219,7 @@ class PekkoHttpServerTracingSpec extends AnyWordSpecLike with Matchers with Scal eventually(timeout(10 seconds)) { val span = testSpanReporter().nextSpan().value span.operationName shouldBe "unhandled" - span.tags.get(plain("http.url")) should endWith(s"$interface:$port/unknown-path") + span.tags.get(plain("http.url")) should endWith(s"$interface:$port/unknown-path") span.metricTags.get(plain("component")) shouldBe "pekko.http.server" span.metricTags.get(plain("http.method")) shouldBe "GET" span.metricTags.get(plainBoolean("error")) shouldBe false @@ -240,11 +241,11 @@ class PekkoHttpServerTracingSpec extends AnyWordSpecLike with Matchers with Scal span } - inside(span.marks){ - case List(_ @ Mark(_, "http.response.ready")) => + inside(span.marks) { + case List(_ @Mark(_, "http.response.ready")) => } - span.tags.get(plain("http.url")) should endWith(s"$interface:$port/$stream") + span.tags.get(plain("http.url")) should endWith(s"$interface:$port/$stream") span.metricTags.get(plain("component")) shouldBe "pekko.http.server" span.metricTags.get(plain("http.method")) shouldBe "GET" } @@ -277,4 +278,3 @@ class PekkoHttpServerTracingSpec extends AnyWordSpecLike with Matchers with Scal httpsWebServer.shutdown() } } - diff --git a/instrumentation/kamon-pekko-http/src/test/scala/kamon/pekko/http/ServerFlowWrapperSpec.scala b/instrumentation/kamon-pekko-http/src/test/scala/kamon/pekko/http/ServerFlowWrapperSpec.scala index 06def45ff..4492ed14e 100644 --- a/instrumentation/kamon-pekko-http/src/test/scala/kamon/pekko/http/ServerFlowWrapperSpec.scala +++ b/instrumentation/kamon-pekko-http/src/test/scala/kamon/pekko/http/ServerFlowWrapperSpec.scala @@ -24,10 +24,14 @@ class ServerFlowWrapperSpec extends AnyWordSpecLike with Matchers with ScalaFutu } private val defaultReturningFlow = Flow[HttpRequest].map { _ => - HttpResponse(status = StatusCodes.OK, entity = HttpEntity.Default( - ContentTypes.`text/plain(UTF-8)`, - 2, - Source.single(ByteString.apply("OK")))) + HttpResponse( + status = StatusCodes.OK, + entity = HttpEntity.Default( + ContentTypes.`text/plain(UTF-8)`, + 2, + Source.single(ByteString.apply("OK")) + ) + ) } "the server flow wrapper" should { diff --git a/instrumentation/kamon-pekko-http/src/test/scala/kamon/testkit/TestNameGenerator.scala b/instrumentation/kamon-pekko-http/src/test/scala/kamon/testkit/TestNameGenerator.scala index b8139f9a0..c1877a64e 100644 --- a/instrumentation/kamon-pekko-http/src/test/scala/kamon/testkit/TestNameGenerator.scala +++ b/instrumentation/kamon-pekko-http/src/test/scala/kamon/testkit/TestNameGenerator.scala @@ -20,8 +20,6 @@ import kamon.instrumentation.http.{HttpMessage, HttpOperationNameGenerator} class TestNameGenerator extends HttpOperationNameGenerator { - - // def serverOperationName(request: HttpRequest): String = { // val path = request.uri.path.toString() // // turns "/dummy-path" into "dummy" diff --git a/instrumentation/kamon-pekko-http/src/test/scala/kamon/testkit/TestWebServer.scala b/instrumentation/kamon-pekko-http/src/test/scala/kamon/testkit/TestWebServer.scala index e4d3f892d..e5578b283 100644 --- a/instrumentation/kamon-pekko-http/src/test/scala/kamon/testkit/TestWebServer.scala +++ b/instrumentation/kamon-pekko-http/src/test/scala/kamon/testkit/TestWebServer.scala @@ -56,56 +56,56 @@ trait TestWebServer extends TracingDirectives { } ~ pathPrefix("extraction") { authenticateBasic("realm", credentials => Option("Okay")) { srt => - (post | get) { - pathPrefix("nested") { - pathPrefix(IntNumber / "fixed") { num => - pathPrefix("anchor" / IntNumber.? / JavaUUID / "fixed") { (number, uuid) => - pathPrefix(LongNumber / HexIntNumber) { (longNum, hex) => - complete("OK") + (post | get) { + pathPrefix("nested") { + pathPrefix(IntNumber / "fixed") { num => + pathPrefix("anchor" / IntNumber.? / JavaUUID / "fixed") { (number, uuid) => + pathPrefix(LongNumber / HexIntNumber) { (longNum, hex) => + complete("OK") + } } } - } - } ~ - pathPrefix("concat") { - path("fixed" ~ JavaUUID ~ HexIntNumber) { (uuid, num) => - complete("OK") - } - } ~ - pathPrefix("on-complete" / IntNumber) { _ => - onComplete(Future("hello")) { _ => - extract(samplingDecision) { decision => - path("more-path") { - complete(decision.toString) + } ~ + pathPrefix("concat") { + path("fixed" ~ JavaUUID ~ HexIntNumber) { (uuid, num) => + complete("OK") + } + } ~ + pathPrefix("on-complete" / IntNumber) { _ => + onComplete(Future("hello")) { _ => + extract(samplingDecision) { decision => + path("more-path") { + complete(decision.toString) + } } } - } - } ~ - pathPrefix("on-success" / IntNumber) { _ => - onSuccess(Future("hello")) { text => - pathPrefix("after") { - complete(text) + } ~ + pathPrefix("on-success" / IntNumber) { _ => + onSuccess(Future("hello")) { text => + pathPrefix("after") { + complete(text) + } } - } - } ~ - pathPrefix("complete-or-recover-with" / IntNumber) { _ => - completeOrRecoverWith(Future("bad".charAt(10).toString)) { failure => - pathPrefix("after") { - failWith(failure) + } ~ + pathPrefix("complete-or-recover-with" / IntNumber) { _ => + completeOrRecoverWith(Future("bad".charAt(10).toString)) { failure => + pathPrefix("after") { + failWith(failure) + } } - } - } ~ - pathPrefix("complete-or-recover-with-success" / IntNumber) { _ => - completeOrRecoverWith(Future("good")) { failure => - pathPrefix("after") { - failWith(failure) + } ~ + pathPrefix("complete-or-recover-with-success" / IntNumber) { _ => + completeOrRecoverWith(Future("good")) { failure => + pathPrefix("after") { + failWith(failure) + } } + } ~ + path("segment" / Segment) { segment => + complete(HttpResponse(entity = HttpEntity(ContentTypes.`text/plain(UTF-8)`, segment))) } - } ~ - path("segment" / Segment){ segment => - complete(HttpResponse(entity = HttpEntity(ContentTypes.`text/plain(UTF-8)`, segment))) } } - } } ~ path(rootOk) { complete(OK) @@ -179,8 +179,13 @@ trait TestWebServer extends TracingDirectives { } } - if(https) - new WebServer(interface, port, "https", Http().newServerAt(interface, port).enableHttps(httpContext()).bind(Route.toFunction(routes))) + if (https) + new WebServer( + interface, + port, + "https", + Http().newServerAt(interface, port).enableHttps(httpContext()).bind(Route.toFunction(routes)) + ) else new WebServer(interface, port, "http", Http().newServerAt(interface, port).bindFlow(routes)) } @@ -215,7 +220,9 @@ trait TestWebServer extends TracingDirectives { } def loadX509Certificate(resourceName: String): Certificate = - CertificateFactory.getInstance("X.509").generateCertificate(getClass.getClassLoader.getResourceAsStream(resourceName)) + CertificateFactory.getInstance("X.509").generateCertificate( + getClass.getClassLoader.getResourceAsStream(resourceName) + ) def samplingDecision(ctx: RequestContext): Trace.SamplingDecision = Kamon.currentSpan().trace.samplingDecision @@ -238,7 +245,12 @@ trait TestWebServer extends TracingDirectives { } } - class WebServer(val interface: String, val port: Int, val protocol: String, bindingFuture: Future[Http.ServerBinding])(implicit ec: ExecutionContext) { + class WebServer( + val interface: String, + val port: Int, + val protocol: String, + bindingFuture: Future[Http.ServerBinding] + )(implicit ec: ExecutionContext) { def shutdown(): Future[_] = { bindingFuture.flatMap(binding => binding.unbind()) } diff --git a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/PekkoClusterShardingMetrics.scala b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/PekkoClusterShardingMetrics.scala index 804b1e77c..efd7a88a4 100644 --- a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/PekkoClusterShardingMetrics.scala +++ b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/PekkoClusterShardingMetrics.scala @@ -14,32 +14,33 @@ import scala.collection.concurrent.TrieMap object PekkoClusterShardingMetrics { - val RegionHostedShards = Kamon.rangeSampler ( + val RegionHostedShards = Kamon.rangeSampler( name = "pekko.cluster.sharding.region.hosted-shards", description = "Tracks the number of shards hosted by a region" ) - val RegionHostedEntities = Kamon.rangeSampler ( + val RegionHostedEntities = Kamon.rangeSampler( name = "pekko.cluster.sharding.region.hosted-entities", description = "Tracks the number of entities hosted by a region" ) - val RegionProcessedMessages = Kamon.counter ( + val RegionProcessedMessages = Kamon.counter( name = "pekko.cluster.sharding.region.processed-messages", description = "Counts the number of messages processed by a region" ) - val ShardHostedEntities = Kamon.histogram ( + val ShardHostedEntities = Kamon.histogram( name = "pekko.cluster.sharding.shard.hosted-entities", description = "Tracks the distribution of entity counts hosted per shard" ) - val ShardProcessedMessages = Kamon.histogram ( + val ShardProcessedMessages = Kamon.histogram( name = "pekko.cluster.sharding.shard.processed-messages", description = "Tracks the distribution of processed messages per shard" ) - class ShardingInstruments(system: String, typeName: String) extends InstrumentGroup(TagSet.of("type", typeName).withTag("system", system)) { + class ShardingInstruments(system: String, typeName: String) + extends InstrumentGroup(TagSet.of("type", typeName).withTag("system", system)) { val hostedShards = register(RegionHostedShards) val hostedEntities = register(RegionHostedEntities) @@ -47,7 +48,8 @@ object PekkoClusterShardingMetrics { val shardHostedEntities = register(ShardHostedEntities) val shardProcessedMessages = register(ShardProcessedMessages) - private val _shardTelemetry = ShardingInstruments.shardTelemetry(system, typeName, shardHostedEntities, shardProcessedMessages) + private val _shardTelemetry = + ShardingInstruments.shardTelemetry(system, typeName, shardHostedEntities, shardProcessedMessages) def hostedEntitiesPerShardCounter(shardID: String): AtomicLong = _shardTelemetry.entitiesPerShard.getOrElseUpdate(shardID, new AtomicLong()) @@ -76,7 +78,7 @@ object PekkoClusterShardingMetrics { * * The totals per Shard are tracked locally and sampled in a fixed interval. */ - case class ShardTelemetry ( + case class ShardTelemetry( entitiesPerShard: TrieMap[String, AtomicLong], messagesPerShard: TrieMap[String, AtomicLong], schedule: Registration @@ -84,29 +86,41 @@ object PekkoClusterShardingMetrics { private val _shardTelemetryMap = TrieMap.empty[String, ShardTelemetry] - private def shardTelemetry(system: String, typeName: String, shardEntities: Histogram, shardMessages: Histogram): ShardTelemetry = { - _shardTelemetryMap.atomicGetOrElseUpdate(shardTelemetryKey(system, typeName), { - val entitiesPerShard = TrieMap.empty[String, AtomicLong] - val messagesPerShard = TrieMap.empty[String, AtomicLong] - val samplingInterval = PekkoRemoteInstrumentation.settings().shardMetricsSampleInterval - - val schedule = Kamon.addScheduledAction( - s"pekko/shards/${typeName}", - Some(s"Updates health metrics for the ${system}/${typeName} shard every ${samplingInterval.getSeconds} seconds"), - new ScheduledAction { - override def run(): Unit = { - entitiesPerShard.foreach {case (shard, value) => shardEntities.record(value.get())} - messagesPerShard.foreach {case (shard, value) => shardMessages.record(value.getAndSet(0L))} - } - - override def stop(): Unit = {} - override def reconfigure(newConfig: Config): Unit = {} - - }, samplingInterval) - - - ShardTelemetry(entitiesPerShard, messagesPerShard, schedule) - }, _.schedule.cancel(): Unit, _ => ()) + private def shardTelemetry( + system: String, + typeName: String, + shardEntities: Histogram, + shardMessages: Histogram + ): ShardTelemetry = { + _shardTelemetryMap.atomicGetOrElseUpdate( + shardTelemetryKey(system, typeName), { + val entitiesPerShard = TrieMap.empty[String, AtomicLong] + val messagesPerShard = TrieMap.empty[String, AtomicLong] + val samplingInterval = PekkoRemoteInstrumentation.settings().shardMetricsSampleInterval + + val schedule = Kamon.addScheduledAction( + s"pekko/shards/${typeName}", + Some( + s"Updates health metrics for the ${system}/${typeName} shard every ${samplingInterval.getSeconds} seconds" + ), + new ScheduledAction { + override def run(): Unit = { + entitiesPerShard.foreach { case (shard, value) => shardEntities.record(value.get()) } + messagesPerShard.foreach { case (shard, value) => shardMessages.record(value.getAndSet(0L)) } + } + + override def stop(): Unit = {} + override def reconfigure(newConfig: Config): Unit = {} + + }, + samplingInterval + ) + + ShardTelemetry(entitiesPerShard, messagesPerShard, schedule) + }, + _.schedule.cancel(): Unit, + _ => () + ) } private def removeShardTelemetry(system: String, typeName: String): Unit = diff --git a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/PekkoInstrumentation.scala b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/PekkoInstrumentation.scala index e5fed7b7b..a3b7db9d2 100644 --- a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/PekkoInstrumentation.scala +++ b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/PekkoInstrumentation.scala @@ -45,7 +45,7 @@ object PekkoInstrumentation { * Returns true if the definition was successful and false if a group with the defined name is already available. */ def defineActorGroup(groupName: String, filter: Filter): Boolean = synchronized { - if(_codeProvidedActorGroups.get(groupName).isEmpty) { + if (_codeProvidedActorGroups.get(groupName).isEmpty) { _codeProvidedActorGroups = _codeProvidedActorGroups + (groupName -> filter) _actorGroups = _codeProvidedActorGroups ++ _configProvidedActorGroups true @@ -79,7 +79,7 @@ object PekkoInstrumentation { /** * pekko Instrumentation settings */ - case class Settings ( + case class Settings( askPatternWarning: AskPatternTimeoutWarningSetting, autoGrouping: Boolean, allowDoomsdayWildcards: Boolean, @@ -96,9 +96,9 @@ object PekkoInstrumentation { val exposeClusterMetrics = pekkoConfig.getBoolean("cluster.track-cluster-metrics") val askPatternWarning = pekkoConfig.getString("ask-pattern-timeout-warning") match { - case "off" => Off - case "lightweight" => Lightweight - case "heavyweight" => Heavyweight + case "off" => Off + case "lightweight" => Lightweight + case "heavyweight" => Heavyweight case other => sys.error(s"Unrecognized option [$other] for the kamon.pekko.ask-pattern-timeout-warning config.") } @@ -114,7 +114,7 @@ object PekkoInstrumentation { private def safeFilter(config: Config, allowDoomsday: Boolean): Filter = { val includes = config.getStringList("includes").asScala - if(!allowDoomsday && includes.contains("**")) { + if (!allowDoomsday && includes.contains("**")) { val newIncludes = "includes = " + includes.filter(_ == "**").map(s => s""""$s"""").mkString("[ ", ", ", " ]") val safeFilterConfig = ConfigFactory.parseString(newIncludes).withFallback(config) diff --git a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/PekkoMetrics.scala b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/PekkoMetrics.scala index b50a81ad7..f7c4b8305 100644 --- a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/PekkoMetrics.scala +++ b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/PekkoMetrics.scala @@ -16,12 +16,13 @@ object PekkoMetrics { * Actor Metrics */ - val ActorTimeInMailbox = Kamon.timer ( + val ActorTimeInMailbox = Kamon.timer( name = "pekko.actor.time-in-mailbox", - description = "Tracks the time since the instant a message is enqueued in an Actor's mailbox until it is dequeued for processing" + description = + "Tracks the time since the instant a message is enqueued in an Actor's mailbox until it is dequeued for processing" ) - val ActorProcessingTime = Kamon.timer ( + val ActorProcessingTime = Kamon.timer( name = "pekko.actor.processing-time", description = "Tracks the time taken for the actor to process the receive function" ) @@ -31,7 +32,7 @@ object PekkoMetrics { description = "Tracks the behavior of an Actor's mailbox size" ) - val ActorErrors = Kamon.counter ( + val ActorErrors = Kamon.counter( name = "pekko.actor.errors", description = "Counts the number of processing errors experienced by an Actor" ) @@ -52,42 +53,48 @@ object PekkoMetrics { val errors = register(ActorErrors) } - /** * Router Metrics */ - val RouterRoutingTime = Kamon.timer ( + val RouterRoutingTime = Kamon.timer( name = "pekko.router.routing-time", description = "Tracks the time taken by a router to process its routing logic" ) - val RouterTimeInMailbox = Kamon.timer ( + val RouterTimeInMailbox = Kamon.timer( name = "pekko.router.time-in-mailbox", - description = "Tracks the time since the instant a message is enqueued in a routee's mailbox until it is dequeued for processing" + description = + "Tracks the time since the instant a message is enqueued in a routee's mailbox until it is dequeued for processing" ) - val RouterProcessingTime = Kamon.timer ( + val RouterProcessingTime = Kamon.timer( name = "pekko.router.processing-time", description = "Tracks the time taken for a routee to process the receive function" ) - val RouterPendingMessages = Kamon.rangeSampler ( + val RouterPendingMessages = Kamon.rangeSampler( name = "pekko.router.pending-messages", description = "Tracks the number of messages waiting to be processed across all routees" ) - val RouterMembers = Kamon.rangeSampler ( + val RouterMembers = Kamon.rangeSampler( name = "pekko.router.members", description = "Tracks the number of routees belonging to a router" ) - val RouterErrors = Kamon.counter ( + val RouterErrors = Kamon.counter( name = "pekko.router.errors", description = "Counts the number of processing errors experienced by the routees of a router" ) - def forRouter(path: String, system: String, dispatcher: String, routerClass: Class[_], routeeClass: String): RouterInstruments = { + def forRouter( + path: String, + system: String, + dispatcher: String, + routerClass: Class[_], + routeeClass: String + ): RouterInstruments = { val tags = TagSet.builder() .add("path", path) .add("system", system) @@ -107,45 +114,46 @@ object PekkoMetrics { val errors = register(RouterErrors) } - /** * Actor Group Metrics */ - val GroupTimeInMailbox = Kamon.timer ( + val GroupTimeInMailbox = Kamon.timer( name = "pekko.group.time-in-mailbox", - description = "Tracks the time since the instant a message is enqueued in a member's mailbox until it is dequeued for processing" + description = + "Tracks the time since the instant a message is enqueued in a member's mailbox until it is dequeued for processing" ) - val GroupProcessingTime = Kamon.timer ( + val GroupProcessingTime = Kamon.timer( name = "pekko.group.processing-time", description = "Tracks the time taken for a member actor to process the receive function" ) - val GroupPendingMessages = Kamon.rangeSampler ( + val GroupPendingMessages = Kamon.rangeSampler( name = "pekko.group.pending-messages", description = "Tracks the number of messages waiting to be processed across all members" ) - val GroupMembers = Kamon.rangeSampler ( + val GroupMembers = Kamon.rangeSampler( name = "pekko.group.members", description = "Tracks the number of routees belonging to a group" ) - val GroupErrors = Kamon.counter ( + val GroupErrors = Kamon.counter( name = "pekko.group.errors", description = "Counts the number of processing errors experienced by the members of a group" ) def forGroup(group: String, system: String): ActorGroupInstruments = - _groupInstrumentsCache.getOrElseUpdate(system + "/" + group, { - val tags = TagSet.builder() - .add("group", group) - .add("system", system) - - new ActorGroupInstruments(tags.build()) - }) + _groupInstrumentsCache.getOrElseUpdate( + system + "/" + group, { + val tags = TagSet.builder() + .add("group", group) + .add("system", system) + new ActorGroupInstruments(tags.build()) + } + ) case class ActorGroupInstruments(tags: TagSet) extends InstrumentGroup(tags) { val timeInMailbox = register(GroupTimeInMailbox) @@ -155,27 +163,26 @@ object PekkoMetrics { val errors = register(GroupErrors) } - /** * Actor System Metrics */ - val SystemDeadLetters = Kamon.counter ( + val SystemDeadLetters = Kamon.counter( name = "pekko.system.dead-letters", description = "Counts the number of dead letters in an Actor System" ) - val SystemUnhandledMessages = Kamon.counter ( + val SystemUnhandledMessages = Kamon.counter( name = "pekko.system.unhandled-messages", description = "Counts the number of unhandled messages in an Actor System" ) - val SystemProcessedMessages = Kamon.counter ( + val SystemProcessedMessages = Kamon.counter( name = "pekko.system.processed-messages", description = "Counts the number of processed messages in an Actor System" ) - val SystemActiveActors = Kamon.rangeSampler ( + val SystemActiveActors = Kamon.rangeSampler( name = "pekko.system.active-actors", description = "Tracks the number of active Actors in an Actor System" ) diff --git a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/PekkoRemoteInstrumentation.scala b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/PekkoRemoteInstrumentation.scala index 780265637..4ece811ee 100644 --- a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/PekkoRemoteInstrumentation.scala +++ b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/PekkoRemoteInstrumentation.scala @@ -5,7 +5,6 @@ import java.time.Duration import com.typesafe.config.Config import kamon.Kamon - object PekkoRemoteInstrumentation { @volatile private var _settings = readSettings(Kamon.config()) diff --git a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/PekkoRemoteMetrics.scala b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/PekkoRemoteMetrics.scala index 9ea27cdca..db123fb6d 100644 --- a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/PekkoRemoteMetrics.scala +++ b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/PekkoRemoteMetrics.scala @@ -9,24 +9,24 @@ import scala.collection.concurrent.TrieMap object PekkoRemoteMetrics { - val InboundMessageSize = Kamon.histogram ( + val InboundMessageSize = Kamon.histogram( name = "pekko.remote.messages.inbound.size", description = "Tracks the distribution of inbound message sizes", unit = information.bytes ) - val OutboundMessageSize = Kamon.histogram ( + val OutboundMessageSize = Kamon.histogram( name = "pekko.remote.messages.outbound.size", description = "Tracks the distribution of outbound message sizes", unit = information.bytes ) - val SerializationTime = Kamon.timer ( + val SerializationTime = Kamon.timer( name = "pekko.remote.serialization-time", description = "Tracks the time taken to serialize outgoing messages" ) - val DeserializationTime = Kamon.timer ( + val DeserializationTime = Kamon.timer( name = "pekko.remote.deserialization-time", description = "Tracks the time taken to deserialize incoming messages" ) diff --git a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/ActorCellInfo.scala b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/ActorCellInfo.scala index 8f1108f34..cee8cef56 100644 --- a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/ActorCellInfo.scala +++ b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/ActorCellInfo.scala @@ -8,7 +8,7 @@ import scala.language.existentials /** * Basic information that should be read from an ActorCell for instrumentation purposes. */ -case class ActorCellInfo ( +case class ActorCellInfo( path: String, name: String, systemName: String, @@ -41,7 +41,7 @@ object ActorCellInfo { val isTemporary = PekkoPrivateAccess.isUnstartedActorCell(cell) val (actorOrRouterClass, routeeClass) = - if(isRouter) + if (isRouter) (props.routerConfig.getClass, Some(ref.asInstanceOf[HasRouterProps].routeeProps.actorClass())) else if (isRoutee) (parent.asInstanceOf[HasRouterProps].routerProps.routerConfig.getClass, Some(props.actorClass())) @@ -49,8 +49,8 @@ object ActorCellInfo { (props.actorClass(), None) val fullPath = if (isRoutee) cellName(system, parent) else cellName(system, ref) - val dispatcherName = if(isRouter) { - if(props.routerConfig.isInstanceOf[BalancingPool]) { + val dispatcherName = if (isRouter) { + if (props.routerConfig.isInstanceOf[BalancingPool]) { // Even though the router actor for a BalancingPool can have a different dispatcher we will // assign the name of the same dispatcher where the routees will run to ensure all metrics are @@ -71,8 +71,19 @@ object ActorCellInfo { val isStreamImplementationActor = actorClassName == StreamsSupervisorActorClassName || actorClassName == StreamsInterpreterActorClassName - ActorCellInfo(fullPath, actorName, system.name, dispatcherName, isRouter, isRoutee, isRootSupervisor, - isStreamImplementationActor, isTemporary, actorOrRouterClass, routeeClass) + ActorCellInfo( + fullPath, + actorName, + system.name, + dispatcherName, + isRouter, + isRoutee, + isRootSupervisor, + isStreamImplementationActor, + isTemporary, + actorOrRouterClass, + routeeClass + ) } /** @@ -81,15 +92,18 @@ object ActorCellInfo { def simpleClassName(cls: Class[_]): String = { // Class.getSimpleName could fail if called on a double-nested class. // See https://github.com/scala/bug/issues/2034 for more details. - try { cls.getSimpleName } catch { case _: Throwable => { - val className = cls.getName - val lastSeparator = className.lastIndexOf('.') - - if(lastSeparator > 0) - className.substring(lastSeparator + 1) - else - className - }} + try { cls.getSimpleName } + catch { + case _: Throwable => { + val className = cls.getName + val lastSeparator = className.lastIndexOf('.') + + if (lastSeparator > 0) + className.substring(lastSeparator + 1) + else + className + } + } } def isTyped(className: Class[_]): Boolean = { diff --git a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/ActorInstrumentation.scala b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/ActorInstrumentation.scala index 4f1821974..afef0c52e 100644 --- a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/ActorInstrumentation.scala +++ b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/ActorInstrumentation.scala @@ -89,7 +89,11 @@ object ActorCellSwapMailboxAdvice { } @Advice.OnMethodExit - @static def exit(@Advice.This cell: Any, @Advice.Return oldMailbox: Any, @Advice.Enter isShuttingDown: Boolean): Unit = { + @static def exit( + @Advice.This cell: Any, + @Advice.Return oldMailbox: Any, + @Advice.Enter isShuttingDown: Boolean + ): Unit = { if (oldMailbox != null && isShuttingDown) { actorMonitor(cell).onDroppedMessages(PekkoPrivateAccess.mailboxMessageCount(oldMailbox)) } @@ -104,7 +108,7 @@ object InvokeAllMethodInterceptor { @static def enter(@Advice.Argument(0) message: Any): Option[Scope] = message match { case m: HasContext => Some(Kamon.storeContext(m.context)) - case _ => None + case _ => None } @Advice.OnMethodExit @@ -130,7 +134,12 @@ class RepointableActorCellConstructorAdvice object RepointableActorCellConstructorAdvice { @Advice.OnMethodExit(suppress = classOf[Throwable]) - @static def onExit(@This cell: Any, @Argument(0) system: ActorSystem, @Argument(1) ref: ActorRef, @Argument(3) parent: ActorRef): Unit = + @static def onExit( + @This cell: Any, + @Argument(0) system: ActorSystem, + @Argument(1) ref: ActorRef, + @Argument(3) parent: ActorRef + ): Unit = cell.asInstanceOf[HasActorMonitor].setActorMonitor(ActorMonitor.from(cell, ref, parent, system)) } @@ -139,7 +148,12 @@ class ActorCellConstructorAdvice object ActorCellConstructorAdvice { @OnMethodExit(suppress = classOf[Throwable]) - @static def onExit(@This cell: Any, @Argument(0) system: ActorSystem, @Argument(1) ref: ActorRef, @Argument(4) parent: ActorRef): Unit = + @static def onExit( + @This cell: Any, + @Argument(0) system: ActorSystem, + @Argument(1) ref: ActorRef, + @Argument(4) parent: ActorRef + ): Unit = cell.asInstanceOf[HasActorMonitor].setActorMonitor(ActorMonitor.from(cell, ref, parent, system)) } diff --git a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/ActorLoggingInstrumentation.scala b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/ActorLoggingInstrumentation.scala index 76dcd2e40..998c1e913 100644 --- a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/ActorLoggingInstrumentation.scala +++ b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/ActorLoggingInstrumentation.scala @@ -48,4 +48,4 @@ object WithMdcMethodAdvice { @OnMethodExit @static def exit(@Enter scope: Scope): Unit = scope.close() -} \ No newline at end of file +} diff --git a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/ActorMonitor.scala b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/ActorMonitor.scala index f17bd61fc..71cbdb0a0 100644 --- a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/ActorMonitor.scala +++ b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/ActorMonitor.scala @@ -41,7 +41,12 @@ trait ActorMonitor { /** * Callback executed when message processing has ended. */ - def onMessageProcessingEnd(context: Context, envelopeTimestamp: Long, processingStartTimestamp: Long, stateFromStart: Any): Unit + def onMessageProcessingEnd( + context: Context, + envelopeTimestamp: Long, + processingStartTimestamp: Long, + stateFromStart: Any + ): Unit /** * Callback executed when an exception is thrown by the monitored Actor. @@ -79,7 +84,7 @@ object ActorMonitor { val autoGroupingPath = resolveAutoGroupingPath(cell.actorOrRouterClass, ref, parent, system.name) def traceWrap(monitor: ActorMonitor): ActorMonitor = - if(participatesInTracing) new TracedMonitor(cell, startsTrace, monitor) else monitor + if (participatesInTracing) new TracedMonitor(cell, startsTrace, monitor) else monitor val monitor = { @@ -91,14 +96,18 @@ object ActorMonitor { } else { - val trackedFilter = if (cell.isRouter || cell.isRoutee) Kamon.filter(TrackRouterFilterName) else settings.safeActorTrackFilter + val trackedFilter = + if (cell.isRouter || cell.isRoutee) Kamon.filter(TrackRouterFilterName) else settings.safeActorTrackFilter val isTracked = !cell.isRootSupervisor && trackedFilter.accept(cell.path) - val trackingGroups: Seq[ActorGroupInstruments] = if (cell.isRootSupervisor) List() else { + val trackingGroups: Seq[ActorGroupInstruments] = if (cell.isRootSupervisor) List() + else { val configuredMatchingGroups = PekkoInstrumentation.matchingActorGroups(cell.path) - if (configuredMatchingGroups.isEmpty && !isTracked + if ( + configuredMatchingGroups.isEmpty && !isTracked && settings.autoGrouping && !cell.isRouter - && !cell.isRoutee && !ActorCellInfo.isTyped(cell.actorOrRouterClass)) { + && !cell.isRoutee && !ActorCellInfo.isTyped(cell.actorOrRouterClass) + ) { if (!trackedFilter.excludes(cell.path) && Kamon.filter(TrackAutoGroupFilterName).accept(autoGroupingPath)) List(PekkoMetrics.forGroup(autoGroupingPath, system.name)) else @@ -122,12 +131,16 @@ object ActorMonitor { traceWrap(monitor) } - - private def createRegularActorMonitor(cellInfo: ActorCellInfo, isTracked: Boolean, participatesInTracing: Boolean, - groupMetrics: Seq[ActorGroupInstruments]): ActorMonitor = { + private def createRegularActorMonitor( + cellInfo: ActorCellInfo, + isTracked: Boolean, + participatesInTracing: Boolean, + groupMetrics: Seq[ActorGroupInstruments] + ): ActorMonitor = { if (isTracked || !groupMetrics.isEmpty) { - val actorMetrics: Option[PekkoMetrics.ActorInstruments] = if (!isTracked) None else { + val actorMetrics: Option[PekkoMetrics.ActorInstruments] = if (!isTracked) None + else { Some(PekkoMetrics.forActor( cellInfo.path, cellInfo.systemName, @@ -158,19 +171,24 @@ object ActorMonitor { new TrackedRoutee(routerMetrics, groupMetrics, cellInfo) } - private def resolveAutoGroupingPath(actorClass: Class[_], ref: ActorRef, parent: ActorRef, systemName: String): String = { + private def resolveAutoGroupingPath( + actorClass: Class[_], + ref: ActorRef, + parent: ActorRef, + systemName: String + ): String = { val name = ref.path.name val elementCount = ref.path.elements.size - val parentPath = if(parent.isInstanceOf[HasGroupPath]) parent.asInstanceOf[HasGroupPath].groupPath else "" + val parentPath = if (parent.isInstanceOf[HasGroupPath]) parent.asInstanceOf[HasGroupPath].groupPath else "" val refGroupName = { - if(elementCount == 1) - if(name == "/") "" else systemName + "/" + name + if (elementCount == 1) + if (name == "/") "" else systemName + "/" + name else ActorCellInfo.simpleClassName(actorClass) } - val refGroupPath = if(parentPath.isEmpty) refGroupName else parentPath + "/" + refGroupName + val refGroupPath = if (parentPath.isEmpty) refGroupName else parentPath + "/" + refGroupName ref.asInstanceOf[HasGroupPath].setGroupPath(refGroupPath) refGroupPath } @@ -191,20 +209,33 @@ object ActorMonitor { override def onMessageProcessingStart(context: Context, envelopeTimestamp: Long, envelope: Envelope): Any = { val incomingContext = context - if(incomingContext.get(Span.Key).isEmpty && !startsTrace) { + if (incomingContext.get(Span.Key).isEmpty && !startsTrace) { // We will not generate a Span unless message processing is happening inside of a trace. new SpanAndMonitorState(null, monitor.onMessageProcessingStart(context, envelopeTimestamp, envelope)) } else { val messageSpan = buildSpan(cellInfo, context, envelopeTimestamp, envelope).start() val contextWithMessageSpan = incomingContext.withEntry(Span.Key, messageSpan) - new SpanAndMonitorState(messageSpan, monitor.onMessageProcessingStart(contextWithMessageSpan, envelopeTimestamp, envelope)) + new SpanAndMonitorState( + messageSpan, + monitor.onMessageProcessingStart(contextWithMessageSpan, envelopeTimestamp, envelope) + ) } } - override def onMessageProcessingEnd(context: Context, envelopeTimestamp: Long, processingStartTimestamp: Long, stateFromStart: Any): Unit = { + override def onMessageProcessingEnd( + context: Context, + envelopeTimestamp: Long, + processingStartTimestamp: Long, + stateFromStart: Any + ): Unit = { val spanAndMonitor = stateFromStart.asInstanceOf[SpanAndMonitorState] - monitor.onMessageProcessingEnd(context, envelopeTimestamp, processingStartTimestamp, spanAndMonitor.wrappedMonitorState) + monitor.onMessageProcessingEnd( + context, + envelopeTimestamp, + processingStartTimestamp, + spanAndMonitor.wrappedMonitorState + ) if (spanAndMonitor.span != null) spanAndMonitor.span.asInstanceOf[Span].finish() } @@ -225,7 +256,12 @@ object ActorMonitor { ActorCellInfo.simpleClassName(envelope.message.getClass) } - private def buildSpan(cellInfo: ActorCellInfo, context: Context, envelopeTimestamp: Long, envelope: Envelope): Span.Delayed = { + private def buildSpan( + cellInfo: ActorCellInfo, + context: Context, + envelopeTimestamp: Long, + envelope: Envelope + ): Span.Delayed = { val messageClass = extractMessageClass(envelope) val parentSpan = context.get(Span.Key) @@ -242,7 +278,7 @@ object ActorMonitor { } private def operationName(messageClass: String, sender: ActorRef): String = { - val operationType = if(PekkoPrivateAccess.isPromiseActorRef(sender)) "ask" else "tell" + val operationType = if (PekkoPrivateAccess.isPromiseActorRef(sender)) "ask" else "tell" StringBuilder.newBuilder .append(operationType) @@ -258,28 +294,34 @@ object ActorMonitor { /** * Basic implementation that only provides Context propagation across Actors. */ - class ContextPropagationOnly(cellInfo: ActorCellInfo, participatesInTracing: Boolean, trackActiveActors: Boolean) extends ActorMonitor { + class ContextPropagationOnly(cellInfo: ActorCellInfo, participatesInTracing: Boolean, trackActiveActors: Boolean) + extends ActorMonitor { private val _systemMetrics = PekkoMetrics.forSystem(cellInfo.systemName) - if(trackActiveActors && !cellInfo.isTemporary) { + if (trackActiveActors && !cellInfo.isTemporary) { _systemMetrics.activeActors.increment() } override def captureEnvelopeTimestamp(): Long = - if(participatesInTracing) Kamon.clock().nanos() else 0L + if (participatesInTracing) Kamon.clock().nanos() else 0L override def captureEnvelopeContext(): Context = Kamon.currentContext() override def captureProcessingStartTimestamp(): Long = - if(participatesInTracing) Kamon.clock().nanos() else 0L + if (participatesInTracing) Kamon.clock().nanos() else 0L override def onMessageProcessingStart(context: Context, envelopeTimestamp: Long, envelope: Envelope): Any = { _systemMetrics.processedMessagesByNonTracked.increment() Kamon.storeContext(context) } - override def onMessageProcessingEnd(context: Context, envelopeTimestamp: Long, processingStartTimestamp: Long, stateFromStart: Any): Unit = + override def onMessageProcessingEnd( + context: Context, + envelopeTimestamp: Long, + processingStartTimestamp: Long, + stateFromStart: Any + ): Unit = stateFromStart.asInstanceOf[Scope].close() override def onFailure(failure: Throwable): Unit = {} @@ -289,7 +331,7 @@ object ActorMonitor { override def onTerminationStart(): Unit = {} def cleanup(): Unit = { - if(trackActiveActors && !cellInfo.isTemporary) + if (trackActiveActors && !cellInfo.isTemporary) _systemMetrics.activeActors.decrement() } } @@ -297,8 +339,11 @@ object ActorMonitor { /** * ActorMonitor that tracks Actor and/or Group metrics and performs Context propagation. */ - class TrackedActor(actorMetrics: Option[ActorInstruments], groupMetrics: Seq[ActorGroupInstruments], cellInfo: ActorCellInfo) - extends GroupMetricsTrackingActor(groupMetrics, cellInfo) { + class TrackedActor( + actorMetrics: Option[ActorInstruments], + groupMetrics: Seq[ActorGroupInstruments], + cellInfo: ActorCellInfo + ) extends GroupMetricsTrackingActor(groupMetrics, cellInfo) { private val _processedMessagesCounter = PekkoMetrics.forSystem(cellInfo.systemName).processedMessagesByTracked @@ -315,8 +360,14 @@ object ActorMonitor { Kamon.storeContext(context) } - override def onMessageProcessingEnd(context: Context, envelopeTimestamp: Long, processingStartTimestamp: Long, stateFromStart: Any): Unit = { - try stateFromStart.asInstanceOf[Scope].close() finally { + override def onMessageProcessingEnd( + context: Context, + envelopeTimestamp: Long, + processingStartTimestamp: Long, + stateFromStart: Any + ): Unit = { + try stateFromStart.asInstanceOf[Scope].close() + finally { val timestampAfterProcessing = clock.nanos() val timeInMailbox = processingStartTimestamp - envelopeTimestamp val processingTime = timestampAfterProcessing - processingStartTimestamp @@ -344,8 +395,11 @@ object ActorMonitor { /** * ActorMonitor that tracks the activity of a Routee and possibly Actor Group metrics. */ - class TrackedRoutee(routerMetrics: RouterInstruments, groupMetrics: Seq[ActorGroupInstruments], cellInfo: ActorCellInfo) - extends GroupMetricsTrackingActor(groupMetrics, cellInfo) { + class TrackedRoutee( + routerMetrics: RouterInstruments, + groupMetrics: Seq[ActorGroupInstruments], + cellInfo: ActorCellInfo + ) extends GroupMetricsTrackingActor(groupMetrics, cellInfo) { routerMetrics.members.increment() private val processedMessagesCounter = PekkoMetrics.forSystem(cellInfo.systemName).processedMessagesByTracked @@ -360,8 +414,14 @@ object ActorMonitor { Kamon.storeContext(context) } - override def onMessageProcessingEnd(context: Context, envelopeTimestamp: Long, processingStartTimestamp: Long, stateFromStart: Any): Unit = { - try stateFromStart.asInstanceOf[Scope].close() finally { + override def onMessageProcessingEnd( + context: Context, + envelopeTimestamp: Long, + processingStartTimestamp: Long, + stateFromStart: Any + ): Unit = { + try stateFromStart.asInstanceOf[Scope].close() + finally { val timestampAfterProcessing = Kamon.clock().nanos() val timeInMailbox = processingStartTimestamp - envelopeTimestamp val processingTime = timestampAfterProcessing - processingStartTimestamp @@ -392,7 +452,8 @@ object ActorMonitor { /** * Base actor tracking class that brings support for Actor Group metrics. */ - abstract class GroupMetricsTrackingActor(groupMetrics: Seq[ActorGroupInstruments], cellInfo: ActorCellInfo) extends ActorMonitor { + abstract class GroupMetricsTrackingActor(groupMetrics: Seq[ActorGroupInstruments], cellInfo: ActorCellInfo) + extends ActorMonitor { @volatile private var _isAlive = true private val _shouldTrackActiveActors = !cellInfo.isTemporary protected val clock = Kamon.clock() @@ -412,7 +473,7 @@ object ActorMonitor { clock.nanos() override def captureEnvelopeContext(): Context = { - if(_isAlive && !cellInfo.isTemporary) { + if (_isAlive && !cellInfo.isTemporary) { groupMetrics.foreach { gm => gm.pendingMessages.increment() } diff --git a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/ActorMonitorInstrumentation.scala b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/ActorMonitorInstrumentation.scala index 369b54c93..de5bd9684 100644 --- a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/ActorMonitorInstrumentation.scala +++ b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/ActorMonitorInstrumentation.scala @@ -11,13 +11,13 @@ import scala.annotation.static import scala.util.control.NonFatal class ActorMonitorInstrumentation extends InstrumentationBuilder { - /* - * Changes implementation of extractMessageClass for our ActorMonitor. - * In Pekko, all typed messages are converted to AdaptMessage, - * so we're forced to extract the original message type. - */ - onSubTypesOf("kamon.instrumentation.pekko.instrumentations.ActorMonitor") - .intercept(method("extractMessageClass"), classOf[MessageClassAdvice]) + /* + * Changes implementation of extractMessageClass for our ActorMonitor. + * In Pekko, all typed messages are converted to AdaptMessage, + * so we're forced to extract the original message type. + */ + onSubTypesOf("kamon.instrumentation.pekko.instrumentations.ActorMonitor") + .intercept(method("extractMessageClass"), classOf[MessageClassAdvice]) } class MessageClassAdvice @@ -29,7 +29,7 @@ object MessageClassAdvice { try { e.message match { case message: WrappedMessage => ActorCellInfo.simpleClassName(message.message.getClass) - case _ => ActorCellInfo.simpleClassName(e.message.getClass) + case _ => ActorCellInfo.simpleClassName(e.message.getClass) } } catch { // NoClassDefFound is thrown in early versions of akka 2.6 diff --git a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/ActorRefInstrumentation.scala b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/ActorRefInstrumentation.scala index 02b153019..557994356 100644 --- a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/ActorRefInstrumentation.scala +++ b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/ActorRefInstrumentation.scala @@ -56,5 +56,3 @@ object RepointableActorRefPointAdvice { .setContext(Context.Empty) } } - - diff --git a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/AskPatternInstrumentation.scala b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/AskPatternInstrumentation.scala index 2f05b85ab..cc639f17b 100644 --- a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/AskPatternInstrumentation.scala +++ b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/AskPatternInstrumentation.scala @@ -47,15 +47,20 @@ object AskPatternInstrumentation { private class StackTraceCaptureException extends Throwable - private case class SourceLocation ( + private case class SourceLocation( declaringType: String, method: String ) @OnMethodExit(suppress = classOf[Throwable]) - @static def onExit(@Origin origin: String, @Return future: Future[AnyRef], @Argument(0) actor: ActorRef, @Argument(2) timeout: Timeout) = { - - if(PekkoPrivateAccess.isInternalAndActiveActorRef(actor) && Kamon.currentContext().nonEmpty()) { + @static def onExit( + @Origin origin: String, + @Return future: Future[AnyRef], + @Argument(0) actor: ActorRef, + @Argument(2) timeout: Timeout + ) = { + + if (PekkoPrivateAccess.isInternalAndActiveActorRef(actor) && Kamon.currentContext().nonEmpty()) { PekkoInstrumentation.settings().askPatternWarning match { case Off => case Lightweight => hookLightweightWarning(future, sourceLocation(origin), actor) @@ -69,7 +74,6 @@ object AskPatternInstrumentation { case _ => } - private def hookLightweightWarning(future: Future[AnyRef], sourceLocation: SourceLocation, actor: ActorRef): Unit = { val locationString = Option(sourceLocation) .map(location => s"${location.declaringType}:${location.method}") @@ -80,7 +84,11 @@ object AskPatternInstrumentation { })(CallingThreadExecutionContext) } - private def hookHeavyweightWarning(future: Future[AnyRef], captureException: StackTraceCaptureException, actor: ActorRef): Unit = { + private def hookHeavyweightWarning( + future: Future[AnyRef], + captureException: StackTraceCaptureException, + actor: ActorRef + ): Unit = { val locationString = captureException.getStackTrace.drop(3).mkString("", System.lineSeparator, System.lineSeparator) future.failed.foreach(ifAskTimeoutException { diff --git a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/ClusterInstrumentation.scala b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/ClusterInstrumentation.scala index d02d0ace4..d651a01f7 100644 --- a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/ClusterInstrumentation.scala +++ b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/ClusterInstrumentation.scala @@ -15,18 +15,22 @@ import scala.collection.mutable class ClusterInstrumentation extends InstrumentationBuilder { - onType("org.apache.pekko.cluster.Cluster$") - .advise(method("createExtension").and(takesArguments(1)), classOf[AfterClusterInitializationAdvice]) + onType("org.apache.pekko.cluster.Cluster$") + .advise(method("createExtension").and(takesArguments(1)), classOf[AfterClusterInitializationAdvice]) } class AfterClusterInitializationAdvice object AfterClusterInitializationAdvice { @Advice.OnMethodExit - @static def onClusterExtensionCreated(@Advice.Argument(0) system: ExtendedActorSystem, @Advice.Return clusterExtension: Cluster): Unit = { + @static def onClusterExtensionCreated( + @Advice.Argument(0) system: ExtendedActorSystem, + @Advice.Return clusterExtension: Cluster + ): Unit = { val settings = PekkoInstrumentation.settings() - if(settings.exposeClusterMetrics) { - val stateExporter = system.systemActorOf(Props[ClusterInstrumentation.ClusterStateExporter](), "kamon-cluster-state-exporter") + if (settings.exposeClusterMetrics) { + val stateExporter = + system.systemActorOf(Props[ClusterInstrumentation.ClusterStateExporter](), "kamon-cluster-state-exporter") clusterExtension.subscribe(stateExporter, classOf[ClusterEvent.ClusterDomainEvent]) } } @@ -74,19 +78,22 @@ object ClusterInstrumentation { // The status and reachability gauges will only be published for the subset of members that are currently being // monitored by this node. - val currentlyMonitoredMembers = clusterState.members.filter(m => clusterExtension.failureDetector.isMonitoring(m.address)) + val currentlyMonitoredMembers = + clusterState.members.filter(m => clusterExtension.failureDetector.isMonitoring(m.address)) val currentlyMonitoredAddresses = currentlyMonitoredMembers.map { member => - val (statusGauge, reachabilityGauge) = monitoredNodes.getOrElseUpdate(member.address, { - val memberTags = clusterTags.withTag("member", member.address.toString) + val (statusGauge, reachabilityGauge) = monitoredNodes.getOrElseUpdate( + member.address, { + val memberTags = clusterTags.withTag("member", member.address.toString) - ( - ClusterMemberStatus.withTags(memberTags), - ClusterMemberReachability.withTags(memberTags) - ) - }) + ( + ClusterMemberStatus.withTags(memberTags), + ClusterMemberReachability.withTags(memberTags) + ) + } + ) statusGauge.update(statusToGaugeValue(member.status)) - reachabilityGauge.update(if(clusterState.unreachable(member)) 1D else 0D) + reachabilityGauge.update(if (clusterState.unreachable(member)) 1d else 0d) member.address } @@ -101,14 +108,14 @@ object ClusterInstrumentation { } private def statusToGaugeValue(memberStatus: MemberStatus): Double = memberStatus match { - case MemberStatus.Joining => 1 - case MemberStatus.WeaklyUp => 2 - case MemberStatus.Up => 3 - case MemberStatus.Leaving => 4 - case MemberStatus.Exiting => 5 - case MemberStatus.Down => 6 - case MemberStatus.Removed => 7 - case _ => 0 // This should never happen, but covering the bases here + case MemberStatus.Joining => 1 + case MemberStatus.WeaklyUp => 2 + case MemberStatus.Up => 3 + case MemberStatus.Leaving => 4 + case MemberStatus.Exiting => 5 + case MemberStatus.Down => 6 + case MemberStatus.Removed => 7 + case _ => 0 // This should never happen, but covering the bases here } } diff --git a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/DispatcherInfo.scala b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/DispatcherInfo.scala index df907ef2a..589736f15 100644 --- a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/DispatcherInfo.scala +++ b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/DispatcherInfo.scala @@ -46,4 +46,4 @@ object DispatcherInfo { override def setDispatcherName(dispatcherName: String): Unit = _dispatcherName = dispatcherName } } -} \ No newline at end of file +} diff --git a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/DispatcherInstrumentation.scala b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/DispatcherInstrumentation.scala index afd1d4a50..31eee18c5 100644 --- a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/DispatcherInstrumentation.scala +++ b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/DispatcherInstrumentation.scala @@ -17,7 +17,16 @@ package kamon.instrumentation.pekko.instrumentations import java.util.concurrent.{AbstractExecutorService, Callable, ExecutorService, ThreadFactory, TimeUnit} -import org.apache.pekko.dispatch.{DefaultExecutorServiceConfigurator, DispatcherPrerequisites, Dispatchers, ExecutorServiceFactory, ExecutorServiceFactoryProvider, ForkJoinExecutorConfigurator, PinnedDispatcherConfigurator, ThreadPoolExecutorConfigurator} +import org.apache.pekko.dispatch.{ + DefaultExecutorServiceConfigurator, + DispatcherPrerequisites, + Dispatchers, + ExecutorServiceFactory, + ExecutorServiceFactoryProvider, + ForkJoinExecutorConfigurator, + PinnedDispatcherConfigurator, + ThreadPoolExecutorConfigurator +} import kamon.Kamon import kamon.instrumentation.pekko.PekkoInstrumentation import kamon.instrumentation.pekko.instrumentations.DispatcherInfo.{HasDispatcherName, HasDispatcherPrerequisites} @@ -31,46 +40,48 @@ import scala.annotation.static class DispatcherInstrumentation extends InstrumentationBuilder { - /** + /** * This is where the actual ExecutorService instances are being created, but at this point we don't have access to * the Actor System Name nor the Dispatcher name, which is why there is additional instrumentation to carry these two * names down to the ExecutorServiceFactory and use them to tag the newly instrumented ExecutorService. */ - onSubTypesOf("org.apache.pekko.dispatch.ExecutorServiceFactory") - .mixin(classOf[HasDispatcherPrerequisites.Mixin]) - .mixin(classOf[HasDispatcherName.Mixin]) - .intercept(method("createExecutorService"), classOf[InstrumentNewExecutorServiceOnPekko]) + onSubTypesOf("org.apache.pekko.dispatch.ExecutorServiceFactory") + .mixin(classOf[HasDispatcherPrerequisites.Mixin]) + .mixin(classOf[HasDispatcherName.Mixin]) + .intercept(method("createExecutorService"), classOf[InstrumentNewExecutorServiceOnPekko]) - /** + /** * First step on getting the Actor System name is to read it from the prerequisites instance passed to the * constructors of these two classes. */ - onTypes( - "org.apache.pekko.dispatch.ThreadPoolExecutorConfigurator", - "org.apache.pekko.dispatch.ForkJoinExecutorConfigurator", - "org.apache.pekko.dispatch.PinnedDispatcherConfigurator", - "org.apache.pekko.dispatch.DefaultExecutorServiceConfigurator") - .mixin(classOf[HasDispatcherPrerequisites.Mixin]) - .advise(isConstructor, classOf[CaptureDispatcherPrerequisitesOnExecutorConfigurator]) - - /** + onTypes( + "org.apache.pekko.dispatch.ThreadPoolExecutorConfigurator", + "org.apache.pekko.dispatch.ForkJoinExecutorConfigurator", + "org.apache.pekko.dispatch.PinnedDispatcherConfigurator", + "org.apache.pekko.dispatch.DefaultExecutorServiceConfigurator" + ) + .mixin(classOf[HasDispatcherPrerequisites.Mixin]) + .advise(isConstructor, classOf[CaptureDispatcherPrerequisitesOnExecutorConfigurator]) + + /** * Copies the Actor System and Dispatcher names to the ExecutorServiceFactory instances for the two types of * executors instrumented by Kamon. */ - onTypes( - "org.apache.pekko.dispatch.ThreadPoolConfig", - "org.apache.pekko.dispatch.ForkJoinExecutorConfigurator", - "org.apache.pekko.dispatch.PinnedDispatcherConfigurator", - "org.apache.pekko.dispatch.DefaultExecutorServiceConfigurator") - .mixin(classOf[HasDispatcherName.Mixin]) - .advise(method("createExecutorServiceFactory"), classOf[CopyDispatcherInfoToExecutorServiceFactory]) - - /** + onTypes( + "org.apache.pekko.dispatch.ThreadPoolConfig", + "org.apache.pekko.dispatch.ForkJoinExecutorConfigurator", + "org.apache.pekko.dispatch.PinnedDispatcherConfigurator", + "org.apache.pekko.dispatch.DefaultExecutorServiceConfigurator" + ) + .mixin(classOf[HasDispatcherName.Mixin]) + .advise(method("createExecutorServiceFactory"), classOf[CopyDispatcherInfoToExecutorServiceFactory]) + + /** * This ensures that the ActorSystem name is not lost when creating PinnedDispatcher instances. */ - onType("org.apache.pekko.dispatch.ThreadPoolConfig") - .mixin(classOf[HasDispatcherPrerequisites.Mixin]) - .advise(method("copy"), classOf[ThreadPoolConfigCopyAdvice]) + onType("org.apache.pekko.dispatch.ThreadPoolConfig") + .mixin(classOf[HasDispatcherPrerequisites.Mixin]) + .advise(method("copy"), classOf[ThreadPoolConfigCopyAdvice]) } @@ -80,10 +91,14 @@ object CaptureDispatcherPrerequisitesOnExecutorConfigurator { @Advice.OnMethodExit(suppress = classOf[Throwable]) @static def exit(@Advice.This configurator: Any, @Advice.Argument(1) prerequisites: DispatcherPrerequisites): Unit = { configurator match { - case fjec: ForkJoinExecutorConfigurator => fjec.asInstanceOf[HasDispatcherPrerequisites].setDispatcherPrerequisites(prerequisites) - case tpec: ThreadPoolExecutorConfigurator => tpec.threadPoolConfig.asInstanceOf[HasDispatcherPrerequisites].setDispatcherPrerequisites(prerequisites) - case pdc: PinnedDispatcherConfigurator => pdc.asInstanceOf[HasDispatcherPrerequisites].setDispatcherPrerequisites(prerequisites) - case desc: DefaultExecutorServiceConfigurator => desc.asInstanceOf[HasDispatcherPrerequisites].setDispatcherPrerequisites(prerequisites) + case fjec: ForkJoinExecutorConfigurator => + fjec.asInstanceOf[HasDispatcherPrerequisites].setDispatcherPrerequisites(prerequisites) + case tpec: ThreadPoolExecutorConfigurator => + tpec.threadPoolConfig.asInstanceOf[HasDispatcherPrerequisites].setDispatcherPrerequisites(prerequisites) + case pdc: PinnedDispatcherConfigurator => + pdc.asInstanceOf[HasDispatcherPrerequisites].setDispatcherPrerequisites(prerequisites) + case desc: DefaultExecutorServiceConfigurator => + desc.asInstanceOf[HasDispatcherPrerequisites].setDispatcherPrerequisites(prerequisites) case _ => // just ignore any other case. } } @@ -93,7 +108,11 @@ class CopyDispatcherInfoToExecutorServiceFactory object CopyDispatcherInfoToExecutorServiceFactory { @Advice.OnMethodExit - @static def exit(@Advice.This poolConfig: HasDispatcherPrerequisites, @Advice.Argument(0) dispatcherName: String, @Advice.Return factory: Any): Unit = { + @static def exit( + @Advice.This poolConfig: HasDispatcherPrerequisites, + @Advice.Argument(0) dispatcherName: String, + @Advice.Return factory: Any + ): Unit = { val factoryWithMixins = factory.asInstanceOf[HasDispatcherName with HasDispatcherPrerequisites] factoryWithMixins.setDispatcherPrerequisites(poolConfig.dispatcherPrerequisites) factoryWithMixins.setDispatcherName(dispatcherName) @@ -103,21 +122,36 @@ object CopyDispatcherInfoToExecutorServiceFactory { class InstrumentNewExecutorServiceOnPekko object InstrumentNewExecutorServiceOnPekko { - @static def around(@This factory: HasDispatcherPrerequisites with HasDispatcherName, @SuperCall callable: Callable[ExecutorService]): ExecutorService = { + @static def around( + @This factory: HasDispatcherPrerequisites with HasDispatcherName, + @SuperCall callable: Callable[ExecutorService] + ): ExecutorService = { val executor = callable.call() val actorSystemName = factory.dispatcherPrerequisites.settings.name val dispatcherName = factory.dispatcherName val scheduledActionName = actorSystemName + "/" + dispatcherName val systemTags = TagSet.of("pekko.system", actorSystemName) - if(Kamon.filter(PekkoInstrumentation.TrackDispatcherFilterName).accept(dispatcherName)) { + if (Kamon.filter(PekkoInstrumentation.TrackDispatcherFilterName).accept(dispatcherName)) { val defaultEcOption = factory.dispatcherPrerequisites.defaultExecutionContext - if(dispatcherName == Dispatchers.DefaultDispatcherId && defaultEcOption.isDefined) { - ExecutorInstrumentation.instrumentExecutionContext(defaultEcOption.get, dispatcherName, systemTags, scheduledActionName, ExecutorInstrumentation.DefaultSettings) + if (dispatcherName == Dispatchers.DefaultDispatcherId && defaultEcOption.isDefined) { + ExecutorInstrumentation.instrumentExecutionContext( + defaultEcOption.get, + dispatcherName, + systemTags, + scheduledActionName, + ExecutorInstrumentation.DefaultSettings + ) .underlyingExecutor.getOrElse(executor) } else { - ExecutorInstrumentation.instrument(executor, dispatcherName, systemTags, scheduledActionName, ExecutorInstrumentation.DefaultSettings) + ExecutorInstrumentation.instrument( + executor, + dispatcherName, + systemTags, + scheduledActionName, + ExecutorInstrumentation.DefaultSettings + ) } } else executor } @@ -128,7 +162,9 @@ object ThreadPoolConfigCopyAdvice { @Advice.OnMethodExit @static def exit(@Advice.This original: Any, @Advice.Return copy: Any): Unit = { - copy.asInstanceOf[HasDispatcherPrerequisites].setDispatcherPrerequisites(original.asInstanceOf[HasDispatcherPrerequisites].dispatcherPrerequisites) + copy.asInstanceOf[HasDispatcherPrerequisites].setDispatcherPrerequisites( + original.asInstanceOf[HasDispatcherPrerequisites].dispatcherPrerequisites + ) copy.asInstanceOf[HasDispatcherName].setDispatcherName(original.asInstanceOf[HasDispatcherName].dispatcherName) } } diff --git a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/EnvelopeInstrumentation.scala b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/EnvelopeInstrumentation.scala index c508d9e5b..6969526df 100644 --- a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/EnvelopeInstrumentation.scala +++ b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/EnvelopeInstrumentation.scala @@ -22,7 +22,6 @@ import kanela.agent.libs.net.bytebuddy.asm.Advice import scala.annotation.static - class EnvelopeInstrumentation extends InstrumentationBuilder { /** @@ -43,4 +42,3 @@ object EnvelopeCopyAdvice { newEnvelope.asInstanceOf[HasTimestamp].setTimestamp(envelope.asInstanceOf[HasTimestamp].timestamp) } } - diff --git a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/EventStreamInstrumentation.scala b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/EventStreamInstrumentation.scala index 4c0084f01..d43de792d 100644 --- a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/EventStreamInstrumentation.scala +++ b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/EventStreamInstrumentation.scala @@ -39,7 +39,7 @@ class ConstructorAdvice object ConstructorAdvice { @OnMethodExit(suppress = classOf[Throwable]) - @static def exit(@This eventStream: HasSystem, @Argument(0) system:ActorSystem): Unit = { + @static def exit(@This eventStream: HasSystem, @Argument(0) system: ActorSystem): Unit = { eventStream.setSystem(system) } } @@ -48,13 +48,13 @@ class PublishMethodAdvice object PublishMethodAdvice { @OnMethodExit(suppress = classOf[Throwable]) - @static def exit(@This any: Any, @Argument(0) event: AnyRef):Unit = + @static def exit(@This any: Any, @Argument(0) event: AnyRef): Unit = try { val stream = any.asInstanceOf[HasSystem] event match { - case _: DeadLetter => PekkoMetrics.forSystem(stream.system.name).deadLetters.increment() + case _: DeadLetter => PekkoMetrics.forSystem(stream.system.name).deadLetters.increment() case _: UnhandledMessage => PekkoMetrics.forSystem(stream.system.name).unhandledMessages.increment() - case _ => () + case _ => () } } catch { case _: ClassCastException => () @@ -73,4 +73,4 @@ object HasSystem { override def setSystem(system: ActorSystem): Unit = this.system = system } -} \ No newline at end of file +} diff --git a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/RouterInstrumentation.scala b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/RouterInstrumentation.scala index 3aa2eec67..3a8fecda2 100644 --- a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/RouterInstrumentation.scala +++ b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/RouterInstrumentation.scala @@ -25,7 +25,6 @@ class RouterInstrumentation extends InstrumentationBuilder { .advise(isConstructor, classOf[RoutedActorRefConstructorAdvice]) } - /** * Helps with capturing the Props for both the router and the routees. */ @@ -77,7 +76,12 @@ class RoutedActorCellConstructorAdvice object RoutedActorCellConstructorAdvice { @OnMethodExit(suppress = classOf[Throwable]) - @static def exit(@This cell: Any, @Argument(0) system: ActorSystem, @Argument(1) ref: ActorRef, @Argument(5) parent: ActorRef): Unit = { + @static def exit( + @This cell: Any, + @Argument(0) system: ActorSystem, + @Argument(1) ref: ActorRef, + @Argument(5) parent: ActorRef + ): Unit = { cell.asInstanceOf[HasRouterMonitor].setRouterMonitor(RouterMonitor.from(cell, ref, parent, system)) } } @@ -96,4 +100,3 @@ object SendMessageOnRouterAdvice { @static def onExit(@This cell: Any, @Enter timestampBeforeProcessing: Long): Unit = routerInstrumentation(cell).processMessageEnd(timestampBeforeProcessing) } - diff --git a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/SystemMessageInstrumentation.scala b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/SystemMessageInstrumentation.scala index 4c82b0c8b..48cc19d64 100644 --- a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/SystemMessageInstrumentation.scala +++ b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/SystemMessageInstrumentation.scala @@ -26,4 +26,4 @@ class SystemMessageInstrumentation extends InstrumentationBuilder { */ onSubTypesOf("org.apache.pekko.dispatch.sysmsg.SystemMessage") .mixin(classOf[HasContext.MixinWithInitializer]) -} \ No newline at end of file +} diff --git a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/internal/CellWrapper.scala b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/internal/CellWrapper.scala index 1a28669e3..bb0c85a12 100644 --- a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/internal/CellWrapper.scala +++ b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/instrumentations/internal/CellWrapper.scala @@ -38,15 +38,15 @@ import kamon.instrumentation.context.HasContext * will be propagated for all queued messages. */ class CellWrapper(val underlying: Cell) extends Cell { - override def sendMessage(msg: Envelope): Unit = try { - val context = msg.asInstanceOf[HasContext].context - Kamon.runWithContext(context) { - underlying.sendMessage(msg) + override def sendMessage(msg: Envelope): Unit = + try { + val context = msg.asInstanceOf[HasContext].context + Kamon.runWithContext(context) { + underlying.sendMessage(msg) + } + } catch { + case _: ClassCastException => underlying.sendMessage(msg) } - } - catch { - case _: ClassCastException => underlying.sendMessage(msg) - } override def sendSystemMessage(msg: SystemMessage): Unit = underlying.sendSystemMessage(msg) @@ -71,5 +71,3 @@ class CellWrapper(val underlying: Cell) extends Cell { override def numberOfMessages: Int = underlying.numberOfMessages override def props: Props = underlying.props } - - diff --git a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/remote/MessageBufferInstrumentation.scala b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/remote/MessageBufferInstrumentation.scala index b50fc9c21..ff2b93ff9 100644 --- a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/remote/MessageBufferInstrumentation.scala +++ b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/remote/MessageBufferInstrumentation.scala @@ -1,6 +1,5 @@ package kamon.instrumentation.pekko.remote - import _root_.kanela.agent.api.instrumentation.InstrumentationBuilder import kamon.instrumentation.context.{CaptureCurrentContextOnExit, HasContext, InvokeWithCapturedContext} diff --git a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/remote/RemotingInstrumentation.scala b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/remote/RemotingInstrumentation.scala index 241bdca11..d0ceee172 100644 --- a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/remote/RemotingInstrumentation.scala +++ b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/remote/RemotingInstrumentation.scala @@ -10,61 +10,63 @@ import kamon.instrumentation.pekko.instrumentations.PekkoPrivateAccess import kamon.instrumentation.context.{CaptureCurrentContextOnExit, HasContext} import kanela.agent.api.instrumentation.InstrumentationBuilder import kanela.agent.libs.net.bytebuddy.asm.Advice -import org.apache.pekko.kamon.instrumentation.pekko.remote.internal.{PekkoPduProtobufCodecConstructMessageMethodInterceptor, PekkoPduProtobufCodecDecodeMessage} +import org.apache.pekko.kamon.instrumentation.pekko.remote.internal.{ + PekkoPduProtobufCodecConstructMessageMethodInterceptor, + PekkoPduProtobufCodecDecodeMessage +} import org.apache.pekko.remote.artery.CaptureCurrentInboundEnvelope import scala.annotation.static - class RemotingInstrumentation extends InstrumentationBuilder { - /** + /** * Send messages might be buffered if they reach the EndpointWriter before it has been initialized and the current * Context might be lost after the buffering, so we make sure we capture the context when the Send command was * created and then apply it during the EndpointWrite.writeSend method execution (see below). */ - onType("org.apache.pekko.remote.EndpointManager$Send") - .mixin(classOf[HasContext.Mixin]) - .advise(isConstructor, classOf[CaptureCurrentContextOnExit]) + onType("org.apache.pekko.remote.EndpointManager$Send") + .mixin(classOf[HasContext.Mixin]) + .advise(isConstructor, classOf[CaptureCurrentContextOnExit]) - onType("org.apache.pekko.remote.EndpointWriter") - .advise(method("writeSend"), classOf[WriteSendWithContext]) + onType("org.apache.pekko.remote.EndpointWriter") + .advise(method("writeSend"), classOf[WriteSendWithContext]) - /** + /** * Reads and writes the Pekko PDU using a modified version of the Protobuf that has an extra field for a Context * instance. */ - onType("org.apache.pekko.remote.transport.PekkoPduProtobufCodec$") - .intercept(method("constructMessage"), new PekkoPduProtobufCodecConstructMessageMethodInterceptor()) - .advise(method("decodeMessage"), classOf[PekkoPduProtobufCodecDecodeMessage]) + onType("org.apache.pekko.remote.transport.PekkoPduProtobufCodec$") + .intercept(method("constructMessage"), new PekkoPduProtobufCodecConstructMessageMethodInterceptor()) + .advise(method("decodeMessage"), classOf[PekkoPduProtobufCodecDecodeMessage]) - /** + /** * Mixin Serialization Instruments to the Actor System and use them to record the serialization and deserialization * time metrics. */ - onType("org.apache.pekko.actor.ActorSystemImpl") - .mixin(classOf[HasSerializationInstruments.Mixin]) - .advise(isConstructor, classOf[InitializeActorSystemAdvice]) + onType("org.apache.pekko.actor.ActorSystemImpl") + .mixin(classOf[HasSerializationInstruments.Mixin]) + .advise(isConstructor, classOf[InitializeActorSystemAdvice]) - /** + /** * Artery */ - onType("org.apache.pekko.remote.artery.ReusableOutboundEnvelope") - .mixin(classOf[HasContext.Mixin]) - .advise(method("copy"), classOf[CopyContextOnReusableEnvelope]) + onType("org.apache.pekko.remote.artery.ReusableOutboundEnvelope") + .mixin(classOf[HasContext.Mixin]) + .advise(method("copy"), classOf[CopyContextOnReusableEnvelope]) - onType("org.apache.pekko.remote.artery.Association") - .advise(method("createOutboundEnvelope$1"), classOf[CaptureCurrentContextOnReusableEnvelope]) + onType("org.apache.pekko.remote.artery.Association") + .advise(method("createOutboundEnvelope$1"), classOf[CaptureCurrentContextOnReusableEnvelope]) - onType("org.apache.pekko.remote.artery.RemoteInstruments") - .advise(method("deserialize"), classOf[CaptureCurrentInboundEnvelope]) + onType("org.apache.pekko.remote.artery.RemoteInstruments") + .advise(method("deserialize"), classOf[CaptureCurrentInboundEnvelope]) - onType("org.apache.pekko.remote.artery.ReusableInboundEnvelope") - .mixin(classOf[HasContext.Mixin]) - .advise(method("copyForLane"), classOf[CopyContextOnReusableEnvelope]) + onType("org.apache.pekko.remote.artery.ReusableInboundEnvelope") + .mixin(classOf[HasContext.Mixin]) + .advise(method("copyForLane"), classOf[CopyContextOnReusableEnvelope]) - onType("org.apache.pekko.remote.artery.MessageDispatcher") - .advise(method("dispatch"), classOf[ArteryMessageDispatcherAdvice]) + onType("org.apache.pekko.remote.artery.MessageDispatcher") + .advise(method("dispatch"), classOf[ArteryMessageDispatcherAdvice]) } @@ -138,12 +140,12 @@ object MeasureSerializationTime { @Advice.OnMethodEnter @static def enter(): Long = { - if(PekkoRemoteInstrumentation.settings().trackSerializationMetrics) System.nanoTime() else 0L + if (PekkoRemoteInstrumentation.settings().trackSerializationMetrics) System.nanoTime() else 0L } @Advice.OnMethodExit @static def exit(@Advice.Argument(0) system: AnyRef, @Advice.Enter startNanoTime: Long): Unit = { - if(startNanoTime != 0L) { + if (startNanoTime != 0L) { system.asInstanceOf[HasSerializationInstruments] .serializationInstruments .serializationTime @@ -157,13 +159,17 @@ object MeasureDeserializationTime { @Advice.OnMethodEnter @static def enter(): Long = { - if(PekkoRemoteInstrumentation.settings().trackSerializationMetrics) System.nanoTime() else 0L + if (PekkoRemoteInstrumentation.settings().trackSerializationMetrics) System.nanoTime() else 0L } @Advice.OnMethodExit - @static def exit(@Advice.Argument(0) system: AnyRef, @Advice.Enter startNanoTime: Long, @Advice.Return msg: Any): Unit = { + @static def exit( + @Advice.Argument(0) system: AnyRef, + @Advice.Enter startNanoTime: Long, + @Advice.Return msg: Any + ): Unit = { - if(PekkoPrivateAccess.isSystemMessage(msg)) { + if (PekkoPrivateAccess.isSystemMessage(msg)) { msg match { case hc: HasContext if hc.context == null => hc.setContext(Kamon.currentContext()) @@ -171,7 +177,7 @@ object MeasureDeserializationTime { } } - if(startNanoTime != 0L) { + if (startNanoTime != 0L) { system.asInstanceOf[HasSerializationInstruments] .serializationInstruments .deserializationTime diff --git a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/remote/ShardingInstrumentation.scala b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/remote/ShardingInstrumentation.scala index 069f30c6d..8e0fb1523 100644 --- a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/remote/ShardingInstrumentation.scala +++ b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/remote/ShardingInstrumentation.scala @@ -12,18 +12,17 @@ import scala.annotation.static class ShardingInstrumentation extends InstrumentationBuilder { - /** + /** * The ShardRegion instrumentation just takes care of counting the Region messages and, when stopped, cleans up the * instruments and Shard sampling schedules. */ - onType("org.apache.pekko.cluster.sharding.ShardRegion") - .mixin(classOf[HasShardingInstruments.Mixin]) - .advise(isConstructor, classOf[InitializeShardRegionAdvice]) - .advise(method("deliverMessage"), classOf[DeliverMessageOnShardRegion]) - .advise(method("postStop"), classOf[RegionPostStopAdvice]) + onType("org.apache.pekko.cluster.sharding.ShardRegion") + .mixin(classOf[HasShardingInstruments.Mixin]) + .advise(isConstructor, classOf[InitializeShardRegionAdvice]) + .advise(method("deliverMessage"), classOf[DeliverMessageOnShardRegion]) + .advise(method("postStop"), classOf[RegionPostStopAdvice]) - - /** + /** * Shards control most of metrics generated by the module and we use the internal helper methods to know when * entities were created or shutdown as well as measuring how many messages were sent to them through each Shard. One * implementation note is that messages sent to unstarted entities are going to be counted more than once because @@ -31,22 +30,21 @@ class ShardingInstrumentation extends InstrumentationBuilder { * the work done by "deliverMessage" (like calling he "extractEntityId" function on each message and determine * whether it should be buffered or forwarded). */ - onType("org.apache.pekko.cluster.sharding.Shard") - .mixin(classOf[HasShardingInstruments.Mixin]) - .mixin(classOf[HasShardCounters.Mixin]) - .advise(isConstructor, classOf[InitializeShardAdvice]) - .advise(method("onLeaseAcquired"), classOf[ShardInitializedAdvice]) - .advise(method("postStop"), classOf[ShardPostStopStoppedAdvice]) - .advise(method("getOrCreateEntity"), classOf[ShardGetOrCreateEntityAdvice]) - .advise(method("entityTerminated"), classOf[ShardEntityTerminatedAdvice]) - .advise(method("org$apache$pekko$cluster$sharding$Shard$$deliverMessage"), classOf[ShardDeliverMessageAdvice]) - .advise(method("deliverMessage"), classOf[ShardDeliverMessageAdvice]) - - onType("org.apache.pekko.cluster.sharding.Shard") - .advise(method("shardInitialized"), classOf[ShardInitializedAdvice]) + onType("org.apache.pekko.cluster.sharding.Shard") + .mixin(classOf[HasShardingInstruments.Mixin]) + .mixin(classOf[HasShardCounters.Mixin]) + .advise(isConstructor, classOf[InitializeShardAdvice]) + .advise(method("onLeaseAcquired"), classOf[ShardInitializedAdvice]) + .advise(method("postStop"), classOf[ShardPostStopStoppedAdvice]) + .advise(method("getOrCreateEntity"), classOf[ShardGetOrCreateEntityAdvice]) + .advise(method("entityTerminated"), classOf[ShardEntityTerminatedAdvice]) + .advise(method("org$apache$pekko$cluster$sharding$Shard$$deliverMessage"), classOf[ShardDeliverMessageAdvice]) + .advise(method("deliverMessage"), classOf[ShardDeliverMessageAdvice]) + + onType("org.apache.pekko.cluster.sharding.Shard") + .advise(method("shardInitialized"), classOf[ShardInitializedAdvice]) } - trait HasShardingInstruments { def shardingInstruments: ShardingInstruments def setShardingInstruments(shardingInstruments: ShardingInstruments): Unit @@ -68,7 +66,8 @@ trait HasShardCounters { object HasShardCounters { - class Mixin(var hostedEntitiesCounter: AtomicLong, var processedMessagesCounter: AtomicLong) extends HasShardCounters { + class Mixin(var hostedEntitiesCounter: AtomicLong, var processedMessagesCounter: AtomicLong) + extends HasShardCounters { override def setCounters(hostedEntitiesCounter: AtomicLong, processedMessagesCounter: AtomicLong): Unit = { this.hostedEntitiesCounter = hostedEntitiesCounter this.processedMessagesCounter = processedMessagesCounter @@ -80,7 +79,10 @@ class InitializeShardRegionAdvice object InitializeShardRegionAdvice { @Advice.OnMethodExit - @static def exit(@Advice.This region: Actor with HasShardingInstruments, @Advice.Argument(0) typeName: String): Unit = { + @static def exit( + @Advice.This region: Actor with HasShardingInstruments, + @Advice.Argument(0) typeName: String + ): Unit = { region.setShardingInstruments(new ShardingInstruments(region.context.system.name, typeName)) val system = region.context.system @@ -95,8 +97,11 @@ class InitializeShardAdvice object InitializeShardAdvice { @Advice.OnMethodExit - @static def exit(@Advice.This shard: Actor with HasShardingInstruments with HasShardCounters, @Advice.Argument(0) typeName: String, - @Advice.Argument(1) shardID: String): Unit = { + @static def exit( + @Advice.This shard: Actor with HasShardingInstruments with HasShardCounters, + @Advice.Argument(0) typeName: String, + @Advice.Argument(1) shardID: String + ): Unit = { val shardingInstruments = new ShardingInstruments(shard.context.system.name, typeName) shard.setShardingInstruments(shardingInstruments) @@ -128,7 +133,6 @@ object RegionPostStopAdvice { shard.shardingInstruments.remove() } - class ShardInitializedAdvice object ShardInitializedAdvice { @@ -149,8 +153,11 @@ class ShardGetOrCreateEntityAdvice object ShardGetOrCreateEntityAdvice { @Advice.OnMethodEnter - @static def enter(@Advice.This shard: Actor with HasShardingInstruments with HasShardCounters, @Advice.Argument(0) entityID: String): Unit = { - if(shard.context.child(entityID).isEmpty) { + @static def enter( + @Advice.This shard: Actor with HasShardingInstruments with HasShardCounters, + @Advice.Argument(0) entityID: String + ): Unit = { + if (shard.context.child(entityID).isEmpty) { // The entity is not created just yet, but we know that it will be created right after this. shard.shardingInstruments.hostedEntities.increment() shard.hostedEntitiesCounter.incrementAndGet() diff --git a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/remote/artery/KamonRemoteInstrument.scala b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/remote/artery/KamonRemoteInstrument.scala index 9cf5d2e8c..81dfb414a 100644 --- a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/remote/artery/KamonRemoteInstrument.scala +++ b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/remote/artery/KamonRemoteInstrument.scala @@ -52,12 +52,24 @@ class KamonRemoteInstrument(system: ExtendedActorSystem) extends RemoteInstrumen } } - override def remoteMessageSent(recipient: ActorRef, message: Object, sender: ActorRef, size: Int, time: Long): Unit = { + override def remoteMessageSent( + recipient: ActorRef, + message: Object, + sender: ActorRef, + size: Int, + time: Long + ): Unit = { serializationInstruments.outboundMessageSize.record(size) serializationInstruments.serializationTime.record(time) } - override def remoteMessageReceived(recipient: ActorRef, message: Object, sender: ActorRef, size: Int, time: Long): Unit = { + override def remoteMessageReceived( + recipient: ActorRef, + message: Object, + sender: ActorRef, + size: Int, + time: Long + ): Unit = { serializationInstruments.inboundMessageSize.record(size) serializationInstruments.deserializationTime.record(time) } @@ -95,5 +107,3 @@ object CaptureCurrentInboundEnvelope { CurrentInboundEnvelope.remove() } } - - diff --git a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/remote/internal/ArterySerializationAdvice.scala b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/remote/internal/ArterySerializationAdvice.scala index 44f4b7a85..895083175 100644 --- a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/remote/internal/ArterySerializationAdvice.scala +++ b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/remote/internal/ArterySerializationAdvice.scala @@ -12,7 +12,6 @@ import kanela.agent.libs.net.bytebuddy.asm.Advice import scala.annotation.static - /** * For Artery messages we will always add two sections to the end of each serialized message: the Context and the size * of the Context. The layout will look something like this: @@ -31,15 +30,19 @@ object SerializeForArteryAdvice { } @Advice.OnMethodExit - @static def exit(@Advice.Argument(0) serialization: Serialization, @Advice.Argument(1) envelope: OutboundEnvelope, - @Advice.Argument(3) envelopeBuffer: EnvelopeBuffer, @Advice.Enter startTime: Long): Unit = { + @static def exit( + @Advice.Argument(0) serialization: Serialization, + @Advice.Argument(1) envelope: OutboundEnvelope, + @Advice.Argument(3) envelopeBuffer: EnvelopeBuffer, + @Advice.Enter startTime: Long + ): Unit = { val instruments = PekkoRemoteMetrics.serializationInstruments(serialization.system.name) val messageBuffer = envelopeBuffer.byteBuffer val context = envelope.asInstanceOf[HasContext].context val positionBeforeContext = messageBuffer.position() - if(context.nonEmpty()) { + if (context.nonEmpty()) { Kamon.defaultBinaryPropagation().write(context, byteBufferWriter(messageBuffer)) } @@ -87,7 +90,7 @@ object DeserializeForArteryAdvice { val contextStart = messageBuffer.limit() - (contextSize + 4) val messageSize = contextStart - messageStart - val context = if(contextSize == 0) + val context = if (contextSize == 0) Context.Empty else { messageBuffer @@ -103,10 +106,14 @@ object DeserializeForArteryAdvice { } @Advice.OnMethodExit(onThrowable = classOf[Throwable]) - @static def exit(@Advice.Argument(0) system: ActorSystem, @Advice.Argument(5) envelopeBuffer: EnvelopeBuffer, - @Advice.Enter deserializationInfo: DeserializationInfo, @Advice.Thrown error: Throwable): Unit = { - - if(error == null) { + @static def exit( + @Advice.Argument(0) system: ActorSystem, + @Advice.Argument(5) envelopeBuffer: EnvelopeBuffer, + @Advice.Enter deserializationInfo: DeserializationInfo, + @Advice.Thrown error: Throwable + ): Unit = { + + if (error == null) { LastDeserializedContext.set(deserializationInfo.context) val instruments = PekkoRemoteMetrics.serializationInstruments(system.name) @@ -115,7 +122,6 @@ object DeserializeForArteryAdvice { } } - def byteBufferReader(bb: ByteBuffer): BinaryPropagation.ByteStreamReader = new BinaryPropagation.ByteStreamReader { override def available(): Int = bb.remaining() @@ -138,14 +144,13 @@ object DeserializeForArteryAdvice { } } - class CaptureContextOnInboundEnvelope object CaptureContextOnInboundEnvelope { @Advice.OnMethodEnter @static def enter(@Advice.This inboundEnvelope: Any): Unit = { val lastContext = DeserializeForArteryAdvice.LastDeserializedContext.get() - if(lastContext != null) { + if (lastContext != null) { inboundEnvelope.asInstanceOf[HasContext].setContext(lastContext) DeserializeForArteryAdvice.LastDeserializedContext.set(null) } diff --git a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/remote/internal/KamonOptionVal.scala b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/remote/internal/KamonOptionVal.scala index 52afc2110..6535d5bf7 100644 --- a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/remote/internal/KamonOptionVal.scala +++ b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/remote/internal/KamonOptionVal.scala @@ -1,6 +1,7 @@ package org.apache.pekko -import org.apache.pekko.util.{ OptionVal => PekkoOptionVal } +import org.apache.pekko.util.{OptionVal => PekkoOptionVal} + /** * The sole purpose of this object is to provide access to the otherwise internal class [[org.apache.pekko.util.OptionVal]]. */ diff --git a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/remote/internal/PekkoPduProtobufCodecConstructMessageMethodInterceptor.scala b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/remote/internal/PekkoPduProtobufCodecConstructMessageMethodInterceptor.scala index 86bf233b1..e8e4515d7 100644 --- a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/remote/internal/PekkoPduProtobufCodecConstructMessageMethodInterceptor.scala +++ b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/remote/internal/PekkoPduProtobufCodecConstructMessageMethodInterceptor.scala @@ -4,7 +4,11 @@ import java.io.ByteArrayOutputStream import org.apache.pekko.KamonOptionVal.OptionVal import org.apache.pekko.actor.{ActorRef, Address} -import pekko.remote.ContextAwareWireFormats_Pekko.{AckAndContextAwareEnvelopeContainer, ContextAwareRemoteEnvelope, RemoteContext} +import pekko.remote.ContextAwareWireFormats_Pekko.{ + AckAndContextAwareEnvelopeContainer, + ContextAwareRemoteEnvelope, + RemoteContext +} import org.apache.pekko.remote.WireFormats.{AcknowledgementInfo, ActorRefData, AddressData, SerializedMessage} import org.apache.pekko.remote.{Ack, SeqNo} import org.apache.pekko.util.ByteString @@ -19,12 +23,14 @@ import kanela.agent.libs.net.bytebuddy.implementation.bind.annotation.{Argument, class PekkoPduProtobufCodecConstructMessageMethodInterceptor { @RuntimeType - def aroundConstructMessage(@Argument(0) localAddress: Address, - @Argument(1) recipient: ActorRef, - @Argument(2) serializedMessage: SerializedMessage, - @Argument(3) senderOption: OptionVal[ActorRef], - @Argument(4) seqOption: Option[SeqNo], - @Argument(5) ackOption: Option[Ack]): AnyRef = { + def aroundConstructMessage( + @Argument(0) localAddress: Address, + @Argument(1) recipient: ActorRef, + @Argument(2) serializedMessage: SerializedMessage, + @Argument(3) senderOption: OptionVal[ActorRef], + @Argument(4) seqOption: Option[SeqNo], + @Argument(5) ackOption: Option[Ack] + ): AnyRef = { val ackAndEnvelopeBuilder = AckAndContextAwareEnvelopeContainer.newBuilder val envelopeBuilder = ContextAwareRemoteEnvelope.newBuilder @@ -49,7 +55,7 @@ class PekkoPduProtobufCodecConstructMessageMethodInterceptor { val messageSize = envelopeBuilder.getMessage.getMessage.size() PekkoRemoteMetrics.serializationInstruments(localAddress.system).outboundMessageSize.record(messageSize) - ByteString.ByteString1C(ackAndEnvelopeBuilder.build.toByteArray) //Reuse Byte Array (naughty!) + ByteString.ByteString1C(ackAndEnvelopeBuilder.build.toByteArray) // Reuse Byte Array (naughty!) } // Copied from org.apache.pekko.remote.transport.PekkoPduProtobufCodec because of private access. @@ -64,7 +70,8 @@ class PekkoPduProtobufCodecConstructMessageMethodInterceptor { private def serializeActorRef(defaultAddress: Address, ref: ActorRef): ActorRefData = { ActorRefData.newBuilder.setPath( if (ref.path.address.host.isDefined) ref.path.toSerializationFormat - else ref.path.toSerializationFormatWithAddress(defaultAddress)).build() + else ref.path.toSerializationFormatWithAddress(defaultAddress) + ).build() } // Copied from org.apache.pekko.remote.transport.PekkoPduProtobufCodec because of private access. @@ -78,4 +85,4 @@ class PekkoPduProtobufCodecConstructMessageMethodInterceptor { .build() case _ => throw new IllegalArgumentException(s"Address [$address] could not be serialized: host or port missing.") } -} \ No newline at end of file +} diff --git a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/remote/internal/PekkoPduProtobufCodecDecodeMessageMethodAdvisor.scala b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/remote/internal/PekkoPduProtobufCodecDecodeMessageMethodAdvisor.scala index 1c861b01b..10f28b66c 100644 --- a/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/remote/internal/PekkoPduProtobufCodecDecodeMessageMethodAdvisor.scala +++ b/instrumentation/kamon-pekko/src/main/scala/kamon/instrumentation/pekko/remote/internal/PekkoPduProtobufCodecDecodeMessageMethodAdvisor.scala @@ -19,12 +19,16 @@ class PekkoPduProtobufCodecDecodeMessage object PekkoPduProtobufCodecDecodeMessage { @OnMethodEnter - @static def enter(@Argument(0) bs: ByteString, @Argument(1) provider: RemoteActorRefProvider, @Argument(2) localAddress: Address): Unit = { + @static def enter( + @Argument(0) bs: ByteString, + @Argument(1) provider: RemoteActorRefProvider, + @Argument(2) localAddress: Address + ): Unit = { val ackAndEnvelope = AckAndContextAwareEnvelopeContainer.parseFrom(bs.toArray) if (ackAndEnvelope.hasEnvelope && ackAndEnvelope.getEnvelope.hasTraceContext) { val remoteCtx = ackAndEnvelope.getEnvelope.getTraceContext - if(remoteCtx.getContext.size() > 0) { + if (remoteCtx.getContext.size() > 0) { val ctx = Kamon.defaultBinaryPropagation().read(ByteStreamReader.of(remoteCtx.getContext.toByteArray)) Kamon.storeContext(ctx) } diff --git a/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/ActorCellInstrumentationSpec.scala b/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/ActorCellInstrumentationSpec.scala index abe57b89c..b4a9ac227 100644 --- a/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/ActorCellInstrumentationSpec.scala +++ b/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/ActorCellInstrumentationSpec.scala @@ -32,9 +32,9 @@ import scala.collection.mutable.ListBuffer import scala.concurrent.ExecutionContext import scala.concurrent.duration._ - class ActorCellInstrumentationSpec extends TestKit(ActorSystem("ActorCellInstrumentationSpec")) with AnyWordSpecLike - with BeforeAndAfterAll with ImplicitSender with Eventually with MetricInspection.Syntax with Matchers with InitAndStopKamonAfterAll { + with BeforeAndAfterAll with ImplicitSender with Eventually with MetricInspection.Syntax with Matchers + with InitAndStopKamonAfterAll { implicit lazy val executionContext: ExecutionContext = system.dispatcher import ContextTesting._ @@ -69,7 +69,6 @@ class ActorCellInstrumentationSpec extends TestKit(ActorSystem("ActorCellInstrum expectMsg("propagate-with-ask") } - "propagate the current context to actors behind a simple router" in new EchoSimpleRouterFixture { Kamon.runWithContext(testContext("propagate-with-router")) { router.route("test", testActor) @@ -98,7 +97,7 @@ class ActorCellInstrumentationSpec extends TestKit(ActorSystem("ActorCellInstrum def actorPathTag(ref: ActorRef): String = system.name + "/" + ref.path.elements.mkString("/") val trackedActors = new ListBuffer[String] - for(j <- 1 to 10) { + for (j <- 1 to 10) { for (i <- 1 to 1000) { val a = system.actorOf(Props[ContextStringEcho], s"repointable-$j-$i") a ! PoisonPill @@ -107,7 +106,7 @@ class ActorCellInstrumentationSpec extends TestKit(ActorSystem("ActorCellInstrum eventually(timeout(1 second)) { val trackedActors = kamon.instrumentation.pekko.PekkoMetrics.ActorProcessingTime.tagValues("path") - for(p <- trackedActors) { + for (p <- trackedActors) { trackedActors.find(_ == p) shouldBe empty } } @@ -157,4 +156,3 @@ class ContextStringEcho extends Actor { sender ! Kamon.currentContext().getTag(plain(TestKey)) } } - diff --git a/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/ActorGroupMetricsSpec.scala b/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/ActorGroupMetricsSpec.scala index 31ef342d1..2540f852b 100644 --- a/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/ActorGroupMetricsSpec.scala +++ b/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/ActorGroupMetricsSpec.scala @@ -31,7 +31,8 @@ import org.scalatest.wordspec.AnyWordSpecLike import scala.concurrent.duration._ import scala.util.Random -class ActorGroupMetricsSpec extends TestKit(ActorSystem("ActorGroupMetricsSpec")) with AnyWordSpecLike with MetricInspection.Syntax +class ActorGroupMetricsSpec extends TestKit(ActorSystem("ActorGroupMetricsSpec")) with AnyWordSpecLike + with MetricInspection.Syntax with InstrumentInspection.Syntax with Matchers with InitAndStopKamonAfterAll with ImplicitSender with Eventually { "the Kamon actor-group metrics" should { @@ -41,8 +42,8 @@ class ActorGroupMetricsSpec extends TestKit(ActorSystem("ActorGroupMetricsSpec") val trackedActor3 = watch(createTestActor("group-of-actors-3")) val nonTrackedActor = createTestActor("someone-else") - eventually (timeout(5 seconds)) { - GroupMembers.withTags(groupTags("group-of-actors")).distribution().max shouldBe(3) + eventually(timeout(5 seconds)) { + GroupMembers.withTags(groupTags("group-of-actors")).distribution().max shouldBe (3) } system.stop(trackedActor1) @@ -52,37 +53,41 @@ class ActorGroupMetricsSpec extends TestKit(ActorSystem("ActorGroupMetricsSpec") system.stop(trackedActor3) expectTerminated(trackedActor3) - eventually (timeout(5 seconds)) { + eventually(timeout(5 seconds)) { GroupMembers.withTags(groupTags("group-of-actors")).distribution().max shouldBe (0) } } - "increase the member count when a routee matching the pattern is created" in new ActorGroupMetricsFixtures { val trackedRouter = createTestPoolRouter("group-of-routees") val nonTrackedRouter = createTestPoolRouter("non-tracked-group-of-routees") - eventually (timeout(5 seconds)) { + eventually(timeout(5 seconds)) { val valueNow = GroupMembers.withTags(groupTags("group-of-routees")).distribution().max - valueNow shouldBe(5) + valueNow shouldBe (5) } val trackedRouter2 = createTestPoolRouter("group-of-routees-2") val trackedRouter3 = createTestPoolRouter("group-of-routees-3") - eventually(GroupMembers.withTags(groupTags("group-of-routees")).distribution().max shouldBe(15)) + eventually(GroupMembers.withTags(groupTags("group-of-routees")).distribution().max shouldBe (15)) system.stop(trackedRouter) system.stop(trackedRouter2) system.stop(trackedRouter3) - eventually(GroupMembers.withTags(groupTags("group-of-routees")).distribution(resetState = true).max shouldBe(0)) + eventually(GroupMembers.withTags(groupTags("group-of-routees")).distribution(resetState = true).max shouldBe (0)) } "allow defining groups by configuration" in { PekkoInstrumentation.matchingActorGroups("system/user/group-provided-by-code-actor") shouldBe empty - PekkoInstrumentation.defineActorGroup("group-by-code", Filter.fromGlob("*/user/group-provided-by-code-actor")) shouldBe true - PekkoInstrumentation.matchingActorGroups("system/user/group-provided-by-code-actor") should contain only("group-by-code") + PekkoInstrumentation.defineActorGroup( + "group-by-code", + Filter.fromGlob("*/user/group-provided-by-code-actor") + ) shouldBe true + PekkoInstrumentation.matchingActorGroups( + "system/user/group-provided-by-code-actor" + ) should contain only ("group-by-code") PekkoInstrumentation.removeActorGroup("group-by-code") PekkoInstrumentation.matchingActorGroups("system/user/group-provided-by-code-actor") shouldBe empty } @@ -98,7 +103,7 @@ class ActorGroupMetricsSpec extends TestKit(ActorSystem("ActorGroupMetricsSpec") val hangQueue = Block(1 milliseconds) Random.shuffle(actors).foreach { groupMember => - 1000 times { + 1000 times { groupMember ! hangQueue } } @@ -106,7 +111,8 @@ class ActorGroupMetricsSpec extends TestKit(ActorSystem("ActorGroupMetricsSpec") actors.foreach(system.stop) eventually { - val pendingMessagesDistribution = GroupPendingMessages.withTags(groupTags("group-of-actors-for-cleaning")).distribution() + val pendingMessagesDistribution = + GroupPendingMessages.withTags(groupTags("group-of-actors-for-cleaning")).distribution() pendingMessagesDistribution.count should be > 0L pendingMessagesDistribution.max shouldBe 0L } @@ -121,7 +127,7 @@ class ActorGroupMetricsSpec extends TestKit(ActorSystem("ActorGroupMetricsSpec") memberCountDistribution.max shouldBe (10) } - 1000 times { + 1000 times { parent ! Die } @@ -185,4 +191,3 @@ class SecondLevelGrouping extends Actor { case any => Random.shuffle(context.children).headOption.foreach(_.forward(any)) } } - diff --git a/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/ActorLoggingInstrumentationSpec.scala b/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/ActorLoggingInstrumentationSpec.scala index 71b4f9711..9135139d0 100644 --- a/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/ActorLoggingInstrumentationSpec.scala +++ b/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/ActorLoggingInstrumentationSpec.scala @@ -15,7 +15,6 @@ */ package kamon.instrumentation.pekko - import org.apache.pekko.actor.{Actor, ActorLogging, ActorSystem, Props} import org.apache.pekko.event.Logging.LogEvent import org.apache.pekko.testkit.{ImplicitSender, TestKit} @@ -26,7 +25,8 @@ import org.scalatest.BeforeAndAfterAll import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpecLike -class ActorLoggingInstrumentationSpec extends TestKit(ActorSystem("ActorCellInstrumentationSpec")) with AnyWordSpecLike with Matchers +class ActorLoggingInstrumentationSpec extends TestKit(ActorSystem("ActorCellInstrumentationSpec")) with AnyWordSpecLike + with Matchers with BeforeAndAfterAll with ImplicitSender { import ContextTesting._ @@ -39,17 +39,17 @@ class ActorLoggingInstrumentationSpec extends TestKit(ActorSystem("ActorCellInst val logEvent = fishForMessage() { case event: LogEvent if event.message.toString startsWith "TestLogEvent" => true - case _: LogEvent => false + case _: LogEvent => false } Kamon.runWithContext(logEvent.asInstanceOf[HasContext].context) { - val keyValueFromContext = Kamon.currentContext().getTag(option(ContextTesting.TestKey)).getOrElse("Missing Context Tag") + val keyValueFromContext = + Kamon.currentContext().getTag(option(ContextTesting.TestKey)).getOrElse("Missing Context Tag") keyValueFromContext should be("propagate-when-logging") } } } - override protected def beforeAll(): Unit = system.eventStream.subscribe(testActor, classOf[LogEvent]) override protected def afterAll(): Unit = shutdown() @@ -60,4 +60,3 @@ class LoggerActor extends Actor with ActorLogging { case "info" => log.info("TestLogEvent") } } - diff --git a/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/ActorMetricsSpec.scala b/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/ActorMetricsSpec.scala index d5dde5804..8517126a5 100644 --- a/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/ActorMetricsSpec.scala +++ b/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/ActorMetricsSpec.scala @@ -29,8 +29,8 @@ import org.scalatest.wordspec.AnyWordSpecLike import scala.concurrent.duration._ - -class ActorMetricsSpec extends TestKit(ActorSystem("ActorMetricsSpec")) with AnyWordSpecLike with MetricInspection.Syntax with InstrumentInspection.Syntax with Matchers +class ActorMetricsSpec extends TestKit(ActorSystem("ActorMetricsSpec")) with AnyWordSpecLike + with MetricInspection.Syntax with InstrumentInspection.Syntax with Matchers with ImplicitSender with Eventually with InitAndStopKamonAfterAll { "the Kamon actor metrics" should { @@ -53,8 +53,8 @@ class ActorMetricsSpec extends TestKit(ActorSystem("ActorMetricsSpec")) with Any createTestActor("measuring-processing-time", true) ! TrackTimings(sleep = Some(100 millis)) val timings = expectMsgType[TrackedTimings] - val processingTimeDistribution = ActorProcessingTime. - withTags(actorTags("ActorMetricsSpec/user/measuring-processing-time")).distribution() + val processingTimeDistribution = + ActorProcessingTime.withTags(actorTags("ActorMetricsSpec/user/measuring-processing-time")).distribution() processingTimeDistribution.count should be(1L) processingTimeDistribution.buckets.size should be(1L) @@ -70,51 +70,50 @@ class ActorMetricsSpec extends TestKit(ActorSystem("ActorMetricsSpec")) with Any ActorErrors.withTags(actorTags("ActorMetricsSpec/user/measuring-errors")).value() should be(10) } - "record the mailbox-size" in new ActorMetricsFixtures { - val trackedActor = createTestActor("measuring-mailbox-size", true) - trackedActor ! TrackTimings(sleep = Some(1 second)) - 10.times(trackedActor ! Discard) - trackedActor ! Ping + "record the mailbox-size" in new ActorMetricsFixtures { + val trackedActor = createTestActor("measuring-mailbox-size", true) + trackedActor ! TrackTimings(sleep = Some(1 second)) + 10.times(trackedActor ! Discard) + trackedActor ! Ping - val timings = expectMsgType[TrackedTimings] - expectMsg(Pong) + val timings = expectMsgType[TrackedTimings] + expectMsg(Pong) - val mailboxSizeDistribution = ActorMailboxSize - .withTags(actorTags("ActorMetricsSpec/user/measuring-mailbox-size")).distribution() + val mailboxSizeDistribution = ActorMailboxSize + .withTags(actorTags("ActorMetricsSpec/user/measuring-mailbox-size")).distribution() - mailboxSizeDistribution.min should be(0L +- 1L) - mailboxSizeDistribution.max should be(11L +- 1L) - } + mailboxSizeDistribution.min should be(0L +- 1L) + mailboxSizeDistribution.max should be(11L +- 1L) + } - "record the time-in-mailbox" in new ActorMetricsFixtures { - val trackedActor = createTestActor("measuring-time-in-mailbox", true) - trackedActor ! TrackTimings(sleep = Some(100 millis)) - val timings = expectMsgType[TrackedTimings] + "record the time-in-mailbox" in new ActorMetricsFixtures { + val trackedActor = createTestActor("measuring-time-in-mailbox", true) + trackedActor ! TrackTimings(sleep = Some(100 millis)) + val timings = expectMsgType[TrackedTimings] - val timeInMailboxDistribution = ActorTimeInMailbox - .withTags(actorTags("ActorMetricsSpec/user/measuring-time-in-mailbox")).distribution() + val timeInMailboxDistribution = ActorTimeInMailbox + .withTags(actorTags("ActorMetricsSpec/user/measuring-time-in-mailbox")).distribution() - timeInMailboxDistribution.count should be(1L) - timeInMailboxDistribution.buckets.head.frequency should be(1L) - timeInMailboxDistribution.buckets.head.value should be(timings.approximateTimeInMailbox +- 10.millis.toNanos) - } + timeInMailboxDistribution.count should be(1L) + timeInMailboxDistribution.buckets.head.frequency should be(1L) + timeInMailboxDistribution.buckets.head.value should be(timings.approximateTimeInMailbox +- 10.millis.toNanos) + } - "clean up the associated recorder when the actor is stopped" in new ActorMetricsFixtures { - val trackedActor = createTestActor("stop") + "clean up the associated recorder when the actor is stopped" in new ActorMetricsFixtures { + val trackedActor = createTestActor("stop") - // Killing the actor should remove it's ActorMetrics and registering again below should create a new one. - val deathWatcher = TestProbe() - deathWatcher.watch(trackedActor) - trackedActor ! PoisonPill - deathWatcher.expectTerminated(trackedActor) + // Killing the actor should remove it's ActorMetrics and registering again below should create a new one. + val deathWatcher = TestProbe() + deathWatcher.watch(trackedActor) + trackedActor ! PoisonPill + deathWatcher.expectTerminated(trackedActor) - eventually(timeout(1 second)) { - ActorProcessingTime.tagValues("path") shouldNot contain("ActorMetricsSpec/user/stop") - } - } + eventually(timeout(1 second)) { + ActorProcessingTime.tagValues("path") shouldNot contain("ActorMetricsSpec/user/stop") + } + } } - override protected def afterAll(): Unit = { shutdown() super.afterAll() @@ -141,7 +140,7 @@ class ActorMetricsSpec extends TestKit(ActorSystem("ActorMetricsSpec")) with Any initialiseListener.expectMsg(Pong) // Cleanup all the metric recording instruments: - if(resetState) { + if (resetState) { val tags = actorTags(s"ActorMetricsSpec/user/$name") ActorTimeInMailbox.withTags(tags).distribution(resetState = true) diff --git a/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/ActorMetricsTestActor.scala b/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/ActorMetricsTestActor.scala index 1993b3ae9..e206b9030 100644 --- a/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/ActorMetricsTestActor.scala +++ b/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/ActorMetricsTestActor.scala @@ -58,4 +58,3 @@ object ActorMetricsTestActor { def approximateProcessingTime: Long = afterReceiveTimestamp - dequeueTimestamp } } - diff --git a/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/ActorSystemMetricsSpec.scala b/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/ActorSystemMetricsSpec.scala index ff2065fcf..03deadb2f 100644 --- a/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/ActorSystemMetricsSpec.scala +++ b/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/ActorSystemMetricsSpec.scala @@ -28,8 +28,8 @@ import org.scalatest.wordspec.AnyWordSpecLike import scala.concurrent.duration._ - -class ActorSystemMetricsSpec extends TestKit(ActorSystem("ActorSystemMetricsSpec")) with AnyWordSpecLike with MetricInspection.Syntax +class ActorSystemMetricsSpec extends TestKit(ActorSystem("ActorSystemMetricsSpec")) with AnyWordSpecLike + with MetricInspection.Syntax with InstrumentInspection.Syntax with Matchers with InitAndStopKamonAfterAll with ImplicitSender with Eventually { val (baseActorCount, totalActorCount) = (8L, 29) diff --git a/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/AskPatternInstrumentationSpec.scala b/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/AskPatternInstrumentationSpec.scala index a5f51a267..1b199f537 100644 --- a/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/AskPatternInstrumentationSpec.scala +++ b/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/AskPatternInstrumentationSpec.scala @@ -16,7 +16,6 @@ package kamon.instrumentation.pekko - import com.typesafe.config.ConfigFactory import kamon.Kamon import kamon.instrumentation.pekko.ContextTesting._ @@ -87,7 +86,8 @@ class AskPatternInstrumentationSpec extends TestKit(ActorSystem("AskPatternInstr } def setAskPatternTimeoutWarningMode(mode: String): Unit = { - val newConfiguration = ConfigFactory.parseString(s"kamon.pekko.ask-pattern-timeout-warning=$mode").withFallback(Kamon.config()) + val newConfiguration = + ConfigFactory.parseString(s"kamon.pekko.ask-pattern-timeout-warning=$mode").withFallback(Kamon.config()) Kamon.reconfigure(newConfiguration) } } diff --git a/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/AutoGroupingSpec.scala b/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/AutoGroupingSpec.scala index 2b6497b45..eb695225d 100644 --- a/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/AutoGroupingSpec.scala +++ b/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/AutoGroupingSpec.scala @@ -26,8 +26,9 @@ import org.scalatest.wordspec.AnyWordSpecLike import scala.concurrent.duration._ -class AutoGroupingSpec extends TestKit(ActorSystem("AutoGroupingSpec")) with AnyWordSpecLike with MetricInspection.Syntax - with InstrumentInspection.Syntax with Matchers with InitAndStopKamonAfterAll with ImplicitSender with Eventually { +class AutoGroupingSpec extends TestKit(ActorSystem("AutoGroupingSpec")) with AnyWordSpecLike + with MetricInspection.Syntax + with InstrumentInspection.Syntax with Matchers with InitAndStopKamonAfterAll with ImplicitSender with Eventually { import AutoGroupingSpec._ @@ -116,7 +117,7 @@ object AutoGroupingSpec { override def preStart(): Unit = { super.preStart() - if(pendingDepth >= 0) { + if (pendingDepth >= 0) { childCount.times { context.actorOf(reproducer(pendingDepth - 1, childCount * 2)) ! "ping" } @@ -136,4 +137,3 @@ object AutoGroupingSpec { def dummy(): Props = Props[Dummy] } - diff --git a/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/DispatcherMetricsSpec.scala b/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/DispatcherMetricsSpec.scala index e714ea7ce..9931872a4 100644 --- a/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/DispatcherMetricsSpec.scala +++ b/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/DispatcherMetricsSpec.scala @@ -33,8 +33,9 @@ import java.util.concurrent.Executors import scala.concurrent.{Await, ExecutionContext, Future} import scala.concurrent.duration._ -class DispatcherMetricsSpec extends TestKit(ActorSystem("DispatcherMetricsSpec")) with AnyWordSpecLike with Matchers with MetricInspection.Syntax - with BeforeAndAfterAll with ImplicitSender with Eventually { +class DispatcherMetricsSpec extends TestKit(ActorSystem("DispatcherMetricsSpec")) with AnyWordSpecLike with Matchers + with MetricInspection.Syntax + with BeforeAndAfterAll with ImplicitSender with Eventually { "the Kamon dispatcher metrics" should { @@ -43,13 +44,13 @@ class DispatcherMetricsSpec extends TestKit(ActorSystem("DispatcherMetricsSpec") "tracked-pinned-dispatcher", "tracked-fjp", "tracked-tpe", - "pekko.actor.internal-dispatcher") + "pekko.actor.internal-dispatcher" + ) val excluded = "explicitly-excluded" val allDispatchers = trackedDispatchers :+ excluded val builtInDispatchers = Seq("pekko.actor.default-dispatcher", "pekko.actor.internal-dispatcher") - "track dispatchers configured in the pekko.dispatcher filter" in { allDispatchers.foreach(id => forceInit(system.dispatchers.lookup(id))) @@ -61,7 +62,7 @@ class DispatcherMetricsSpec extends TestKit(ActorSystem("DispatcherMetricsSpec") threads.contains(dispatcherName) && queues.contains(dispatcherName) && tasks.contains(dispatcherName) - } should be (true) + } should be(true) Seq(threads, queues, tasks).flatten should not contain excluded } @@ -71,10 +72,9 @@ class DispatcherMetricsSpec extends TestKit(ActorSystem("DispatcherMetricsSpec") .filter(_.get(plain("pekko.system")) == system.name) .map(_.get(plain("name"))) - instrumentExecutorsWithSystem should contain only(trackedDispatchers: _*) + instrumentExecutorsWithSystem should contain only (trackedDispatchers: _*) } - "clean up the metrics recorders after a dispatcher is shutdown" in { ExecutorMetrics.Parallelism.tagValues("name") should contain("tracked-fjp") shutdownDispatcher(system.dispatchers.lookup("tracked-fjp")) @@ -83,7 +83,8 @@ class DispatcherMetricsSpec extends TestKit(ActorSystem("DispatcherMetricsSpec") } "play nicely when dispatchers are looked up from a BalancingPool router" in { - val balancingPoolRouter = system.actorOf(BalancingPool(5).props(Props[RouterMetricsTestActor]), "test-balancing-pool") + val balancingPoolRouter = + system.actorOf(BalancingPool(5).props(Props[RouterMetricsTestActor]), "test-balancing-pool") balancingPoolRouter ! Ping expectMsg(Pong) @@ -98,7 +99,7 @@ class DispatcherMetricsSpec extends TestKit(ActorSystem("DispatcherMetricsSpec") .filter(_.get(plain("pekko.system")) == system.name) .map(_.get(plain("name"))) - instrumentExecutorsWithSystem should contain only(builtInDispatchers: _*) + instrumentExecutorsWithSystem should contain only (builtInDispatchers: _*) Await.result(system.terminate(), 5 seconds) } @@ -111,16 +112,15 @@ class DispatcherMetricsSpec extends TestKit(ActorSystem("DispatcherMetricsSpec") .map(_.get(plain("name"))) val builtInWithoutDefaultDispatcher = builtInDispatchers.filterNot(_.endsWith("default-dispatcher")) - if(builtInWithoutDefaultDispatcher.isEmpty) + if (builtInWithoutDefaultDispatcher.isEmpty) instrumentExecutorsWithSystem shouldBe empty else - instrumentExecutorsWithSystem should contain only(builtInWithoutDefaultDispatcher: _*) + instrumentExecutorsWithSystem should contain only (builtInWithoutDefaultDispatcher: _*) Await.result(system.terminate(), 5 seconds) } } - def forceInit(dispatcher: MessageDispatcher): MessageDispatcher = { val listener = TestProbe() Future { diff --git a/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/EnvelopeSpec.scala b/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/EnvelopeSpec.scala index ff89049da..6a612cc24 100644 --- a/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/EnvelopeSpec.scala +++ b/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/EnvelopeSpec.scala @@ -16,7 +16,6 @@ package kamon.instrumentation.pekko - import org.apache.pekko.actor.{ActorSystem, ExtendedActorSystem, Props} import org.apache.pekko.dispatch.Envelope import org.apache.pekko.testkit.{ImplicitSender, TestKit} @@ -47,7 +46,9 @@ class EnvelopeSpec extends TestKit(ActorSystem("EnvelopeSpec")) with AnyWordSpec val oos = new ObjectOutputStream(bos) oos.writeObject(env) oos.close() - org.apache.pekko.serialization.JavaSerializer.currentSystem.withValue(system.asInstanceOf[ExtendedActorSystem]) { + org.apache.pekko.serialization.JavaSerializer.currentSystem.withValue( + system.asInstanceOf[ExtendedActorSystem] + ) { val ois = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray())) val obj = ois.readObject() ois.close() diff --git a/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/MessageTracingSpec.scala b/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/MessageTracingSpec.scala index 5fc20ecd4..f6384a03f 100644 --- a/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/MessageTracingSpec.scala +++ b/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/MessageTracingSpec.scala @@ -23,10 +23,10 @@ import java.util.concurrent.TimeUnit import scala.concurrent.duration.Duration import scala.concurrent.{Await, Future} - -class MessageTracingSpec extends TestKit(ActorSystem("MessageTracing")) with AnyWordSpecLike with MetricInspection.Syntax - with Matchers with SpanInspection with Reconfigure with InitAndStopKamonAfterAll with ImplicitSender with Eventually - with OptionValues with ScalaFutures with TestSpanReporter { +class MessageTracingSpec extends TestKit(ActorSystem("MessageTracing")) with AnyWordSpecLike + with MetricInspection.Syntax + with Matchers with SpanInspection with Reconfigure with InitAndStopKamonAfterAll with ImplicitSender with Eventually + with OptionValues with ScalaFutures with TestSpanReporter { "Message tracing instrumentation" should { "skip filtered out actors" in { @@ -43,8 +43,8 @@ class MessageTracingSpec extends TestKit(ActorSystem("MessageTracing")) with Any val spanTags = stringTag(span) _ spanTags("component") shouldBe "pekko.actor" span.operationName shouldBe "tell(String)" - spanTags("pekko.actor.path") shouldNot include ("filteredout") - spanTags("pekko.actor.path") should be ("MessageTracing/user/traced-probe-1") + spanTags("pekko.actor.path") shouldNot include("filteredout") + spanTags("pekko.actor.path") should be("MessageTracing/user/traced-probe-1") } } @@ -150,8 +150,9 @@ class MessageTracingSpec extends TestKit(ActorSystem("MessageTracing")) with Any } "create actor message spans when behind a group router " in { - val routee = system.actorOf(Props[TracingTestActor],"traced-routee-one") - val router = system.actorOf(RoundRobinGroup(Vector(routee.path.toStringWithoutAddress)).props(), "nontraced-group-router") + val routee = system.actorOf(Props[TracingTestActor], "traced-routee-one") + val router = + system.actorOf(RoundRobinGroup(Vector(routee.path.toStringWithoutAddress)).props(), "nontraced-group-router") router ! "ping" expectMsg("pong") @@ -159,8 +160,8 @@ class MessageTracingSpec extends TestKit(ActorSystem("MessageTracing")) with Any eventually(timeout(2 seconds)) { val spanTags = stringTag(testSpanReporter().nextSpan().value) _ spanTags("component") shouldBe "pekko.actor" - spanTags("pekko.actor.path") shouldNot include ("nontraced-pool-router") - spanTags("pekko.actor.path") should be ("MessageTracing/user/traced-routee-one") + spanTags("pekko.actor.path") shouldNot include("nontraced-pool-router") + spanTags("pekko.actor.path") should be("MessageTracing/user/traced-routee-one") } } @@ -173,7 +174,7 @@ class MessageTracingSpec extends TestKit(ActorSystem("MessageTracing")) with Any eventually(timeout(2 seconds)) { val spanTags = stringTag(testSpanReporter().nextSpan().value) _ spanTags("component") shouldBe "pekko.actor" - spanTags("pekko.actor.path") should be ("MessageTracing/user/traced-pool-router") + spanTags("pekko.actor.path") should be("MessageTracing/user/traced-pool-router") } } @@ -184,7 +185,7 @@ class MessageTracingSpec extends TestKit(ActorSystem("MessageTracing")) with Any val _ = Kamon.runWithSpan(Kamon.serverSpanBuilder("wrapper", "test").start()) { actorWithMaterializer.ask("stream").mapTo[String] } - + 5 times { val allSpans = testSpanReporter() .spans() @@ -226,7 +227,7 @@ class ActorWithMaterializer extends Actor { override def receive: Receive = { case "stream" => - Await.result ( + Await.result( Source(1 to 10) .async .map(x => x + x) diff --git a/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/RouterMetricsSpec.scala b/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/RouterMetricsSpec.scala index a422a6864..d17555e2b 100644 --- a/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/RouterMetricsSpec.scala +++ b/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/RouterMetricsSpec.scala @@ -30,8 +30,9 @@ import org.scalatest.wordspec.AnyWordSpecLike import scala.concurrent.duration._ -class RouterMetricsSpec extends TestKit(ActorSystem("RouterMetricsSpec")) with AnyWordSpecLike with MetricInspection.Syntax - with InstrumentInspection.Syntax with Matchers with InitAndStopKamonAfterAll with ImplicitSender with Eventually { +class RouterMetricsSpec extends TestKit(ActorSystem("RouterMetricsSpec")) with AnyWordSpecLike + with MetricInspection.Syntax + with InstrumentInspection.Syntax with Matchers with InitAndStopKamonAfterAll with ImplicitSender with Eventually { "the Kamon router metrics" should { "respect the configured include and exclude filters" in new RouterMetricsFixtures { @@ -41,10 +42,11 @@ class RouterMetricsSpec extends TestKit(ActorSystem("RouterMetricsSpec")) with A RouterProcessingTime.tagValues("path") should contain("RouterMetricsSpec/user/tracked-pool-router") RouterProcessingTime.tagValues("path") shouldNot contain("RouterMetricsSpec/user/non-tracked-pool-router") - RouterProcessingTime.tagValues("path") shouldNot contain("RouterMetricsSpec/user/tracked-explicitly-excluded-pool-router") + RouterProcessingTime.tagValues("path") shouldNot contain( + "RouterMetricsSpec/user/tracked-explicitly-excluded-pool-router" + ) } - "record the routing-time of the receive function for pool routers" in new RouterMetricsFixtures { val listener = TestProbe() val router = createTestPoolRouter("measuring-routing-time-in-pool-router", true) @@ -83,7 +85,9 @@ class RouterMetricsSpec extends TestKit(ActorSystem("RouterMetricsSpec")) with A eventually { RouterErrors - .withTags(routerTags("RouterMetricsSpec/user/measuring-errors-in-pool-router")).value(resetState = false) should be(10L) + .withTags(routerTags("RouterMetricsSpec/user/measuring-errors-in-pool-router")).value(resetState = + false + ) should be(10L) } } @@ -120,7 +124,6 @@ class RouterMetricsSpec extends TestKit(ActorSystem("RouterMetricsSpec")) with A routerTags("RouterMetricsSpec/user/measuring-time-in-mailbox-in-balancing-pool-router").withTags( TagSet.from(Map("dispatcher" -> "BalancingPool-/measuring-time-in-mailbox-in-balancing-pool-router")) ) - ).distribution() timeInMailboxDistribution.count should be(1L) @@ -128,18 +131,17 @@ class RouterMetricsSpec extends TestKit(ActorSystem("RouterMetricsSpec")) with A timeInMailboxDistribution.buckets.head.value should be(timings.approximateTimeInMailbox +- 10.millis.toNanos) } - "record pending-messages for pool routers" in new RouterMetricsFixtures { val timingsListener = TestProbe() val router = createTestPoolRouter("measuring-pending-messages-in-pool-router", true) def pendingMessagesDistribution = RouterPendingMessages .withTags(routerTags("RouterMetricsSpec/user/measuring-pending-messages-in-pool-router")).distribution() - 10 times { router.tell(RouterTrackTimings(sleep = Some(1 second)), timingsListener.ref)} + 10 times { router.tell(RouterTrackTimings(sleep = Some(1 second)), timingsListener.ref) } 10 times { timingsListener.expectMsgType[RouterTrackedTimings] } eventually(pendingMessagesDistribution.max should be >= (5L)) - eventually(pendingMessagesDistribution.max should be (0L)) + eventually(pendingMessagesDistribution.max should be(0L)) } "record pending-messages for balancing pool routers" in new RouterMetricsFixtures { @@ -151,11 +153,11 @@ class RouterMetricsSpec extends TestKit(ActorSystem("RouterMetricsSpec")) with A .withTag("dispatcher", "BalancingPool-/measuring-pending-messages-in-balancing-pool-router") ).distribution() - 10 times { router.tell(RouterTrackTimings(sleep = Some(1 second)), timingsListener.ref)} + 10 times { router.tell(RouterTrackTimings(sleep = Some(1 second)), timingsListener.ref) } 10 times { timingsListener.expectMsgType[RouterTrackedTimings] } eventually(pendingMessagesDistribution.max should be >= (5L)) - eventually(pendingMessagesDistribution.max should be (0L)) + eventually(pendingMessagesDistribution.max should be(0L)) } "record member count for pool routers" in new RouterMetricsFixtures { @@ -164,12 +166,12 @@ class RouterMetricsSpec extends TestKit(ActorSystem("RouterMetricsSpec")) with A def membersDistribution = RouterMembers .withTags(routerTags("RouterMetricsSpec/user/measuring-members-in-pool-router")).distribution() - for(routeesLeft <- 4 to 0 by -1) { + for (routeesLeft <- 4 to 0 by -1) { 100 times { router.tell(Discard, timingsListener.ref) } router.tell(Die, timingsListener.ref) eventually { - membersDistribution.max should be (routeesLeft) + membersDistribution.max should be(routeesLeft) } } } @@ -183,20 +185,20 @@ class RouterMetricsSpec extends TestKit(ActorSystem("RouterMetricsSpec")) with A .withTags(TagSet.from(Map("dispatcher" -> "BalancingPool-/measuring-members-in-balancing-pool-router"))) ).distribution() - for(routeesLeft <- 4 to 0 by -1) { + for (routeesLeft <- 4 to 0 by -1) { 100 times { router.tell(Discard, timingsListener.ref) } router.tell(Die, timingsListener.ref) eventually { - membersDistribution.max should be (routeesLeft) + membersDistribution.max should be(routeesLeft) } } } - "pick the right dispatcher name when the routees have a custom dispatcher set via deployment configuration" in new RouterMetricsFixtures { val testProbe = TestProbe() - val router = system.actorOf(FromConfig.props(Props[RouterMetricsTestActor]), "picking-the-right-dispatcher-in-pool-router") + val router = + system.actorOf(FromConfig.props(Props[RouterMetricsTestActor]), "picking-the-right-dispatcher-in-pool-router") 10 times { router.tell(Ping, testProbe.ref) @@ -208,7 +210,7 @@ class RouterMetricsSpec extends TestKit(ActorSystem("RouterMetricsSpec")) with A ) routerMetrics - .map(_._1.get(plain("dispatcher"))) should contain only("custom-dispatcher") + .map(_._1.get(plain("dispatcher"))) should contain only ("custom-dispatcher") } "clean the pending messages metric when a routee dies in pool routers" in new RouterMetricsFixtures { @@ -217,9 +219,9 @@ class RouterMetricsSpec extends TestKit(ActorSystem("RouterMetricsSpec")) with A def pendingMessagesDistribution = RouterPendingMessages .withTags(routerTags("RouterMetricsSpec/user/cleanup-pending-messages-in-pool-router")).distribution() - 10 times { router.tell(RouterTrackTimings(sleep = Some(1 second)), timingsListener.ref)} - 1 times { router.tell(Die, timingsListener.ref)} - 500 times { router.tell(Discard, timingsListener.ref)} + 10 times { router.tell(RouterTrackTimings(sleep = Some(1 second)), timingsListener.ref) } + 1 times { router.tell(Die, timingsListener.ref) } + 500 times { router.tell(Discard, timingsListener.ref) } eventually { pendingMessagesDistribution.max should be >= (500L) @@ -228,7 +230,7 @@ class RouterMetricsSpec extends TestKit(ActorSystem("RouterMetricsSpec")) with A 10 times { timingsListener.expectMsgType[RouterTrackedTimings] } eventually { - pendingMessagesDistribution.max should be (0L) + pendingMessagesDistribution.max should be(0L) } } @@ -237,13 +239,13 @@ class RouterMetricsSpec extends TestKit(ActorSystem("RouterMetricsSpec")) with A val router = createTestBalancingPoolRouter("cleanup-pending-messages-in-balancing-pool-router", true) def pendingMessagesDistribution = RouterPendingMessages .withTags(routerTags("RouterMetricsSpec/user/cleanup-pending-messages-in-balancing-pool-router") - .withTags(TagSet.from(Map("dispatcher" -> "BalancingPool-/cleanup-pending-messages-in-balancing-pool-router"))) + .withTags( + TagSet.from(Map("dispatcher" -> "BalancingPool-/cleanup-pending-messages-in-balancing-pool-router")) + )).distribution() - ).distribution() - - 10 times { router.tell(RouterTrackTimings(sleep = Some(1 second)), timingsListener.ref)} - 1 times { router.tell(Die, timingsListener.ref)} - 500 times { router.tell(Discard, timingsListener.ref)} + 10 times { router.tell(RouterTrackTimings(sleep = Some(1 second)), timingsListener.ref) } + 1 times { router.tell(Die, timingsListener.ref) } + 500 times { router.tell(Discard, timingsListener.ref) } eventually { pendingMessagesDistribution.max should be >= (100L) @@ -252,7 +254,7 @@ class RouterMetricsSpec extends TestKit(ActorSystem("RouterMetricsSpec")) with A 10 times { timingsListener.expectMsgType[RouterTrackedTimings] } eventually { - pendingMessagesDistribution.max should be (0L) + pendingMessagesDistribution.max should be(0L) } } @@ -266,7 +268,6 @@ class RouterMetricsSpec extends TestKit(ActorSystem("RouterMetricsSpec")) with A trackedRouter ! PoisonPill deathWatcher.expectTerminated(trackedRouter) - eventually { RouterProcessingTime.tagValues("path") shouldNot contain("RouterMetricsSpec/user/stop-in-pool-router") } @@ -281,7 +282,8 @@ class RouterMetricsSpec extends TestKit(ActorSystem("RouterMetricsSpec")) with A } def routerTags(path: String): TagSet = { - val routerClass = if(path.contains("balancing")) "org.apache.pekko.routing.BalancingPool" else "org.apache.pekko.routing.RoundRobinPool" + val routerClass = if (path.contains("balancing")) "org.apache.pekko.routing.BalancingPool" + else "org.apache.pekko.routing.RoundRobinPool" TagSet.from( Map( @@ -294,7 +296,6 @@ class RouterMetricsSpec extends TestKit(ActorSystem("RouterMetricsSpec")) with A ) } - trait RouterMetricsFixtures { def createTestGroupRouter(routerName: String, resetState: Boolean = false): ActorRef = { val routees = Vector.fill(5) { @@ -309,7 +310,7 @@ class RouterMetricsSpec extends TestKit(ActorSystem("RouterMetricsSpec")) with A initialiseListener.expectMsg(Pong) // Cleanup all the metric recording instruments: - if(resetState) { + if (resetState) { RouterRoutingTime.withTags(routerTags(s"RouterMetricsSpec/user/$routerName")).distribution(resetState = true) RouterTimeInMailbox.withTags(routerTags(s"RouterMetricsSpec/user/$routerName")).distribution(resetState = true) RouterProcessingTime.withTags(routerTags(s"RouterMetricsSpec/user/$routerName")).distribution(resetState = true) @@ -328,12 +329,14 @@ class RouterMetricsSpec extends TestKit(ActorSystem("RouterMetricsSpec")) with A initialiseListener.expectMsg(Pong) // Cleanup all the metric recording instruments: - if(resetState) { + if (resetState) { RouterRoutingTime.withTags(routerTags(s"RouterMetricsSpec/user/$routerName")).distribution(resetState = true) RouterTimeInMailbox.withTags(routerTags(s"RouterMetricsSpec/user/$routerName")).distribution(resetState = true) RouterProcessingTime.withTags(routerTags(s"RouterMetricsSpec/user/$routerName")).distribution(resetState = true) RouterErrors.withTags(routerTags(s"RouterMetricsSpec/user/$routerName")).value(resetState = true) - RouterPendingMessages.withTags(routerTags(s"RouterMetricsSpec/user/$routerName")).distribution(resetState = true) + RouterPendingMessages.withTags(routerTags(s"RouterMetricsSpec/user/$routerName")).distribution(resetState = + true + ) RouterMembers.withTags(routerTags(s"RouterMetricsSpec/user/$routerName")).distribution(resetState = true) } @@ -349,9 +352,9 @@ class RouterMetricsSpec extends TestKit(ActorSystem("RouterMetricsSpec")) with A initialiseListener.expectMsg(Pong) // Cleanup all the metric recording instruments: - if(resetState) { + if (resetState) { val tags = routerTags(s"RouterMetricsSpec/user/$routerName") - .withTag("dispatcher", s"BalancingPool-/$routerName") + .withTag("dispatcher", s"BalancingPool-/$routerName") RouterRoutingTime.withTags(tags).distribution(resetState = true) RouterTimeInMailbox.withTags(tags).distribution(resetState = true) @@ -365,4 +368,3 @@ class RouterMetricsSpec extends TestKit(ActorSystem("RouterMetricsSpec")) with A } } } - diff --git a/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/RouterMetricsTestActor.scala b/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/RouterMetricsTestActor.scala index fa14de42b..2048a64a7 100644 --- a/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/RouterMetricsTestActor.scala +++ b/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/RouterMetricsTestActor.scala @@ -50,4 +50,3 @@ object RouterMetricsTestActor { def approximateProcessingTime: Long = afterReceiveTimestamp - dequeueTimestamp } } - diff --git a/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/SchedulerInstrumentationSpec.scala b/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/SchedulerInstrumentationSpec.scala index 4c40373a0..be82b3f59 100644 --- a/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/SchedulerInstrumentationSpec.scala +++ b/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/SchedulerInstrumentationSpec.scala @@ -30,7 +30,6 @@ import scala.concurrent.duration._ class SchedulerInstrumentationSpec extends TestKit(ActorSystem("SchedulerInstrumentationSpec")) with AnyWordSpecLike with Matchers with InitAndStopKamonAfterAll with ImplicitSender with Eventually { - "the Pekko Scheduler instrumentation" should { "propagate the current context in calls to scheduler.scheduleOnce" in { val contextTagPromise = Promise[String]() @@ -39,7 +38,7 @@ class SchedulerInstrumentationSpec extends TestKit(ActorSystem("SchedulerInstrum Kamon.runWithContextTag("key", "one") { system.scheduler.scheduleOnce(100 millis) { contextTagPromise.success(Kamon.currentContext().getTag(plain("key"))) - } (system.dispatcher) + }(system.dispatcher) } eventually(timeout(5 seconds)) { diff --git a/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/SystemMessageInstrumentationSpec.scala b/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/SystemMessageInstrumentationSpec.scala index 063104857..c8dfff008 100644 --- a/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/SystemMessageInstrumentationSpec.scala +++ b/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/SystemMessageInstrumentationSpec.scala @@ -16,7 +16,6 @@ package kamon.instrumentation.pekko - import kamon.Kamon import kamon.instrumentation.pekko.ContextTesting._ import kamon.tag.Lookups._ @@ -30,8 +29,9 @@ import org.scalatest.wordspec.AnyWordSpecLike import scala.concurrent.ExecutionContextExecutor import scala.util.control.NonFatal -class SystemMessageInstrumentationSpec extends TestKit(ActorSystem("ActorSystemMessageInstrumentationSpec")) with AnyWordSpecLike with Matchers - with BeforeAndAfterAll with ImplicitSender { +class SystemMessageInstrumentationSpec extends TestKit(ActorSystem("ActorSystemMessageInstrumentationSpec")) + with AnyWordSpecLike with Matchers + with BeforeAndAfterAll with ImplicitSender { implicit lazy val executionContext: ExecutionContextExecutor = system.dispatcher "the system message passing instrumentation" should { @@ -99,7 +99,7 @@ class SystemMessageInstrumentationSpec extends TestKit(ActorSystem("ActorSystemM expectMsg("fail-and-stop") // From the parent executing the supervision strategy expectMsg("fail-and-stop") // From the postStop hook - //TODO: FIXME expectNoMessage(1 second) + // TODO: FIXME expectNoMessage(1 second) } "the failure is escalated" in { @@ -112,7 +112,7 @@ class SystemMessageInstrumentationSpec extends TestKit(ActorSystem("ActorSystemM expectMsg("fail-and-escalate") // From the grandparent executing the supervision strategy expectMsg("fail-and-escalate") // From the postStop hook in the child expectMsg("fail-and-escalate") // From the postStop hook in the parent - //TODO: FIXME expectNoMessage(1 second) + // TODO: FIXME expectNoMessage(1 second) } } } @@ -120,8 +120,13 @@ class SystemMessageInstrumentationSpec extends TestKit(ActorSystem("ActorSystemM private def propagatedContextKey(): String = Kamon.currentContext().getTag(option(TestKey)).getOrElse("MissingContext") - def supervisorWithDirective(directive: SupervisorStrategy.Directive, sendPreRestart: Boolean = false, sendPostRestart: Boolean = false, - sendPostStop: Boolean = false, sendPreStart: Boolean = false): ActorRef = { + def supervisorWithDirective( + directive: SupervisorStrategy.Directive, + sendPreRestart: Boolean = false, + sendPostRestart: Boolean = false, + sendPostStop: Boolean = false, + sendPreStart: Boolean = false + ): ActorRef = { class GrandParent extends Actor { val child: ActorRef = context.actorOf(Props(new Parent)) @@ -182,4 +187,3 @@ class SystemMessageInstrumentationSpec extends TestKit(ActorSystem("ActorSystemM system.actorOf(Props(new GrandParent)) } } - diff --git a/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/TestLogger.scala b/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/TestLogger.scala index 38a823cc2..925d9270b 100644 --- a/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/TestLogger.scala +++ b/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/TestLogger.scala @@ -7,7 +7,7 @@ import org.apache.pekko.event.slf4j.Slf4jLogger class TestLogger extends Slf4jLogger { override def receive: PartialFunction[Any, Unit] = { val filteredReceive: Actor.Receive = { - case event: LogEvent if(shouldDropEvent(event)) => + case event: LogEvent if (shouldDropEvent(event)) => } filteredReceive.orElse(super.receive) diff --git a/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/sharding/ShardingInstrumentationSpec.scala b/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/sharding/ShardingInstrumentationSpec.scala index 06b82f444..436e77ad7 100644 --- a/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/sharding/ShardingInstrumentationSpec.scala +++ b/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/sharding/ShardingInstrumentationSpec.scala @@ -62,21 +62,27 @@ class ShardingInstrumentationSpec val StaticAllocationStrategy = new ShardAllocationStrategy { override def allocateShard( - requester: ActorRef, - shardId: ShardId, - currentShardAllocations: Map[ActorRef, immutable.IndexedSeq[ShardId]]) - : Future[ActorRef] = { + requester: ActorRef, + shardId: ShardId, + currentShardAllocations: Map[ActorRef, immutable.IndexedSeq[ShardId]] + ): Future[ActorRef] = { Future.successful(requester) } override def rebalance( - currentShardAllocations: Map[ActorRef, immutable.IndexedSeq[ShardId]], - rebalanceInProgress: Set[ShardId]): Future[Set[ShardId]] = { + currentShardAllocations: Map[ActorRef, immutable.IndexedSeq[ShardId]], + rebalanceInProgress: Set[ShardId] + ): Future[Set[ShardId]] = { Future.successful(Set.empty) } } - def registerTypes(shardedType: String, props: Props, system: ActorSystem, allocationStrategy: ShardAllocationStrategy): ActorRef = + def registerTypes( + shardedType: String, + props: Props, + system: ActorSystem, + allocationStrategy: ShardAllocationStrategy + ): ActorRef = ClusterSharding(system).start( typeName = shardedType, entityProps = props, @@ -87,7 +93,7 @@ class ShardingInstrumentationSpec handOffStopMessage = PoisonPill ) - class ShardedTypeContext { + class ShardedTypeContext { val shardType = s"TestType-${Random.nextLong()}" val region = registerTypes(shardType, TestActor.props(testActor), system, StaticAllocationStrategy) val shardTags = TagSet.builder() @@ -149,9 +155,9 @@ class ShardingInstrumentationSpec region ! GracefulShutdown expectTerminated(region) - RegionHostedShards.tagValues("type") should not contain(shardType) - RegionHostedEntities.tagValues("type") should not contain(shardType) - RegionProcessedMessages.tagValues("type") should not contain(shardType) + RegionHostedShards.tagValues("type") should not contain (shardType) + RegionHostedEntities.tagValues("type") should not contain (shardType) + RegionProcessedMessages.tagValues("type") should not contain (shardType) } } diff --git a/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/sharding/ShardingMessageBufferingSpec.scala b/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/sharding/ShardingMessageBufferingSpec.scala index 8d30c377c..9da42b02f 100644 --- a/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/sharding/ShardingMessageBufferingSpec.scala +++ b/instrumentation/kamon-pekko/src/test/scala/kamon/instrumentation/pekko/sharding/ShardingMessageBufferingSpec.scala @@ -18,8 +18,10 @@ class ShardingMessageBufferingSpec extends TestKitBase with AnyWordSpecLike with with MetricInspection.Syntax with InitAndStopKamonAfterAll { implicit lazy val system: ActorSystem = { - ActorSystem("cluster-sharding-spec-system", ConfigFactory.parseString( - """ + ActorSystem( + "cluster-sharding-spec-system", + ConfigFactory.parseString( + """ |pekko { | loglevel = INFO | loggers = [ "org.apache.pekko.event.slf4j.Slf4jLogger" ] @@ -35,11 +37,15 @@ class ShardingMessageBufferingSpec extends TestKitBase with AnyWordSpecLike with | } | } |} - """.stripMargin)) + """.stripMargin + ) + ) } - val remoteSystem: ActorSystem = ActorSystem("cluster-sharding-spec-remote-system", ConfigFactory.parseString( - """ + val remoteSystem: ActorSystem = ActorSystem( + "cluster-sharding-spec-remote-system", + ConfigFactory.parseString( + """ |pekko { | loglevel = INFO | loggers = [ "org.apache.pekko.event.slf4j.Slf4jLogger" ] @@ -55,18 +61,21 @@ class ShardingMessageBufferingSpec extends TestKitBase with AnyWordSpecLike with | } | } |} - """.stripMargin)) + """.stripMargin + ) + ) def contextWithBroadcast(name: String): Context = Context.Empty.withTag( - ContextEchoActor.EchoTag, name + ContextEchoActor.EchoTag, + name ) val extractEntityId: ShardRegion.ExtractEntityId = { - case entityId:String => (entityId, "reply-trace-token") + case entityId: String => (entityId, "reply-trace-token") } val extractShardId: ShardRegion.ExtractShardId = { - case entityId:String => (entityId.toInt % 10).toString + case entityId: String => (entityId.toInt % 10).toString } "The MessageBuffer instrumentation" should { @@ -79,7 +88,8 @@ class ShardingMessageBufferingSpec extends TestKitBase with AnyWordSpecLike with entityProps = ContextEchoActor.props(None), settings = ClusterShardingSettings(system), extractEntityId = extractEntityId, - extractShardId = extractShardId) + extractShardId = extractShardId + ) Kamon.runWithContext(contextWithBroadcast("cluster-sharding-actor-123")) { replierRegion ! "123" diff --git a/instrumentation/kamon-play/src/main/scala/kamon/instrumentation/play/GuiceModule.scala b/instrumentation/kamon-play/src/main/scala/kamon/instrumentation/play/GuiceModule.scala index 2fd244b34..c46a011f3 100644 --- a/instrumentation/kamon-play/src/main/scala/kamon/instrumentation/play/GuiceModule.scala +++ b/instrumentation/kamon-play/src/main/scala/kamon/instrumentation/play/GuiceModule.scala @@ -32,7 +32,11 @@ class GuiceModule extends Module { object GuiceModule { @Singleton - class KamonLoader @Inject() (lifecycle: ApplicationLifecycle, environment: Environment, configuration: Configuration) { + class KamonLoader @Inject() ( + lifecycle: ApplicationLifecycle, + environment: Environment, + configuration: Configuration + ) { Logger(classOf[KamonLoader]).info("Reconfiguring Kamon with Play's Config") Logger(classOf[KamonLoader]).info(configuration.underlying.getString("play.server.provider")) Logger(classOf[KamonLoader]).info(configuration.underlying.getString("kamon.trace.tick-interval")) diff --git a/instrumentation/kamon-play/src/main/scala/kamon/instrumentation/play/PlayClientInstrumentation.scala b/instrumentation/kamon-play/src/main/scala/kamon/instrumentation/play/PlayClientInstrumentation.scala index 6c3e86c7a..fe568f1b7 100644 --- a/instrumentation/kamon-play/src/main/scala/kamon/instrumentation/play/PlayClientInstrumentation.scala +++ b/instrumentation/kamon-play/src/main/scala/kamon/instrumentation/play/PlayClientInstrumentation.scala @@ -57,7 +57,7 @@ object WSClientUrlInterceptor { override def apply(request: StandaloneWSRequest): Future[StandaloneWSResponse] = { val currentContext = Kamon.currentContext() val requestHandler = _httpClientInstrumentation.createHandler(toRequestBuilder(request), currentContext) - val responseFuture = Kamon.runWithSpan(requestHandler.span, finishSpan = false) { + val responseFuture = Kamon.runWithSpan(requestHandler.span, finishSpan = false) { rf(requestHandler.request) } diff --git a/instrumentation/kamon-play/src/main/scala/kamon/instrumentation/play/PlayServerInstrumentation.scala b/instrumentation/kamon-play/src/main/scala/kamon/instrumentation/play/PlayServerInstrumentation.scala index 6790bf28c..2743afba1 100644 --- a/instrumentation/kamon-play/src/main/scala/kamon/instrumentation/play/PlayServerInstrumentation.scala +++ b/instrumentation/kamon-play/src/main/scala/kamon/instrumentation/play/PlayServerInstrumentation.scala @@ -45,29 +45,31 @@ import scala.util.{Failure, Success} class PlayServerInstrumentation extends InstrumentationBuilder { - /** + /** * When using the Akka HTTP server, we will use the exact same instrumentation that comes from the Akka HTTP module, * the only difference here is that we will change the component name. */ private val isAkkaHttpAround = ClassRefiner.builder().mustContain("play.core.server.AkkaHttpServerProvider").build() onType("play.core.server.AkkaHttpServer") - .when(isAkkaHttpAround) - .advise(anyMethods("createServerBinding", "play$core$server$AkkaHttpServer$$createServerBinding"), CreateServerBindingAdvice) - + .when(isAkkaHttpAround) + .advise( + anyMethods("createServerBinding", "play$core$server$AkkaHttpServer$$createServerBinding"), + CreateServerBindingAdvice + ) - /** + /** * When using the Netty HTTP server we are rolling our own instrumentation which simply requires us to create the * HttpServerInstrumentation instance and call the expected callbacks on it. */ private val isNettyAround = ClassRefiner.builder().mustContain("play.core.server.NettyServerProvider").build() onType("play.core.server.NettyServer") - .when(isNettyAround) - .mixin(classOf[HasServerInstrumentation.Mixin]) - .advise(isConstructor, NettyServerInitializationAdvice) + .when(isNettyAround) + .mixin(classOf[HasServerInstrumentation.Mixin]) + .advise(isConstructor, NettyServerInitializationAdvice) - if(hasGenericFutureListener()) { + if (hasGenericFutureListener()) { onType("play.core.server.netty.PlayRequestHandler") .when(isNettyAround) .mixin(classOf[HasServerInstrumentation.Mixin]) @@ -84,12 +86,12 @@ class PlayServerInstrumentation extends InstrumentationBuilder { .advise(method("filterHandler").and(takesArguments(2)), GenerateOperationNameOnFilterHandler) private def hasGenericFutureListener(): Boolean = { - try { Class.forName("io.netty.util.concurrent.GenericFutureListener") != null} catch { case _ => false } + try { Class.forName("io.netty.util.concurrent.GenericFutureListener") != null } + catch { case _ => false } } } - object CreateServerBindingAdvice { @Advice.OnMethodEnter @@ -122,7 +124,11 @@ object NettyServerInitializationAdvice { object NettyPlayRequestHandlerHandleAdvice { @Advice.OnMethodEnter - def enter(@Advice.This requestHandler: Any, @Advice.Argument(0) channel: Channel, @Advice.Argument(1) request: HttpRequest): RequestProcessingContext = { + def enter( + @Advice.This requestHandler: Any, + @Advice.Argument(0) channel: Channel, + @Advice.Argument(1) request: HttpRequest + ): RequestProcessingContext = { val playRequestHandler = requestHandler.asInstanceOf[HasServerInstrumentation] val serverInstrumentation = playRequestHandler.serverInstrumentation() @@ -131,11 +137,12 @@ object NettyPlayRequestHandlerHandleAdvice { deferSamplingDecision = true ) - if(!playRequestHandler.hasBeenUsedBefore()) { + if (!playRequestHandler.hasBeenUsedBefore()) { playRequestHandler.markAsUsed() channel.closeFuture().addListener(new GenericFutureListener[io.netty.util.concurrent.Future[_ >: Void]] { override def operationComplete(future: io.netty.util.concurrent.Future[_ >: Void]): Unit = { - val connectionEstablishedTime = Kamon.clock().toInstant(playRequestHandler.asInstanceOf[HasTimestamp].timestamp) + val connectionEstablishedTime = + Kamon.clock().toInstant(playRequestHandler.asInstanceOf[HasTimestamp].timestamp) val aliveTime = Duration.between(connectionEstablishedTime, Kamon.clock().instant()) serverInstrumentation.connectionClosed(aliveTime, playRequestHandler.handledRequests()) } @@ -147,7 +154,10 @@ object NettyPlayRequestHandlerHandleAdvice { } @Advice.OnMethodExit - def exit(@Advice.Enter rpContext: RequestProcessingContext, @Advice.Return result: scala.concurrent.Future[HttpResponse]): Unit = { + def exit( + @Advice.Enter rpContext: RequestProcessingContext, + @Advice.Return result: scala.concurrent.Future[HttpResponse] + ): Unit = { val reqHandler = rpContext.requestHandler result.onComplete { @@ -166,30 +176,32 @@ object NettyPlayRequestHandlerHandleAdvice { case class RequestProcessingContext(requestHandler: RequestHandler, scope: Storage.Scope) - private def toRequest(request: HttpRequest, serverHost: String, serverPort: Int): HttpMessage.Request = new HttpMessage.Request { - override def url: String = request.uri() - override def path: String = request.uri() - override def method: String = request.method().name() - override def host: String = serverHost - override def port: Int = serverPort + private def toRequest(request: HttpRequest, serverHost: String, serverPort: Int): HttpMessage.Request = + new HttpMessage.Request { + override def url: String = request.uri() + override def path: String = request.uri() + override def method: String = request.method().name() + override def host: String = serverHost + override def port: Int = serverPort - override def read(header: String): Option[String] = - Option(request.headers().get(header)) + override def read(header: String): Option[String] = + Option(request.headers().get(header)) - override def readAll(): Map[String, String] = - request.headers().entries().asScala.map(e => e.getKey -> e.getValue).toMap - } + override def readAll(): Map[String, String] = + request.headers().entries().asScala.map(e => e.getKey -> e.getValue).toMap + } - private def toResponse(response: HttpResponse): HttpMessage.ResponseBuilder[HttpResponse] = new HttpMessage.ResponseBuilder[HttpResponse] { - override def build(): HttpResponse = - response + private def toResponse(response: HttpResponse): HttpMessage.ResponseBuilder[HttpResponse] = + new HttpMessage.ResponseBuilder[HttpResponse] { + override def build(): HttpResponse = + response - override def statusCode: Int = - response.status().code() + override def statusCode: Int = + response.status().code() - override def write(header: String, value: String): Unit = - response.headers().add(header, value) - } + override def write(header: String, value: String): Unit = + response.headers().add(header, value) + } } object PlayRequestHandlerConstructorAdvice { @@ -202,7 +214,6 @@ object PlayRequestHandlerConstructorAdvice { } } - trait HasServerInstrumentation { def serverInstrumentation(): HttpServerInstrumentation def setServerInstrumentation(serverInstrumentation: HttpServerInstrumentation): Unit @@ -214,7 +225,8 @@ trait HasServerInstrumentation { object HasServerInstrumentation { - class Mixin(var serverInstrumentation: HttpServerInstrumentation, var hasBeenUsedBefore: Boolean) extends HasServerInstrumentation { + class Mixin(var serverInstrumentation: HttpServerInstrumentation, var hasBeenUsedBefore: Boolean) + extends HasServerInstrumentation { private var _handledRequests: AtomicLong = null override def setServerInstrumentation(serverInstrumentation: HttpServerInstrumentation): Unit = @@ -236,7 +248,6 @@ object HasServerInstrumentation { } } - object GenerateOperationNameOnFilterHandler { private val defaultRouterNameGenerator = new DefaultRouterOperationNameGenerator() @@ -266,4 +277,4 @@ object GenerateOperationNameOnFilterHandler { }) } -} \ No newline at end of file +} diff --git a/instrumentation/kamon-play/src/main/scala/kamon/instrumentation/play/RouterOperationNameGenerator.scala b/instrumentation/kamon-play/src/main/scala/kamon/instrumentation/play/RouterOperationNameGenerator.scala index 906b93bd4..faf2b4640 100644 --- a/instrumentation/kamon-play/src/main/scala/kamon/instrumentation/play/RouterOperationNameGenerator.scala +++ b/instrumentation/kamon-play/src/main/scala/kamon/instrumentation/play/RouterOperationNameGenerator.scala @@ -14,10 +14,12 @@ class DefaultRouterOperationNameGenerator extends RouterOperationNameGenerator { private val _normalizePattern = """\$([^<]+)<[^>]+>""".r def generateOperationName(handlerDef: HandlerDef): String = { - _operationNameCache.getOrElseUpdate(handlerDef.path, { - // Convert paths of form /foo/bar/$paramname/blah to /foo/bar/paramname/blah - _normalizePattern.replaceAllIn(handlerDef.path, "$1") - }) + _operationNameCache.getOrElseUpdate( + handlerDef.path, { + // Convert paths of form /foo/bar/$paramname/blah to /foo/bar/paramname/blah + _normalizePattern.replaceAllIn(handlerDef.path, "$1") + } + ) } } diff --git a/instrumentation/kamon-redis/src/main/scala/kamon/instrumentation/jedis/JedisInstrumentation.scala b/instrumentation/kamon-redis/src/main/scala/kamon/instrumentation/jedis/JedisInstrumentation.scala index 4c8e6b677..9c7a3c1ae 100644 --- a/instrumentation/kamon-redis/src/main/scala/kamon/instrumentation/jedis/JedisInstrumentation.scala +++ b/instrumentation/kamon-redis/src/main/scala/kamon/instrumentation/jedis/JedisInstrumentation.scala @@ -54,8 +54,8 @@ class JedisInstrumentation extends InstrumentationBuilder { "toString", "hashCode" ))), - classOf[ClientOperationsAdvice]) - + classOf[ClientOperationsAdvice] + ) /** * For Jedis 3.x. This advice ensures we get the right command name in the Span. @@ -66,7 +66,8 @@ class JedisInstrumentation extends InstrumentationBuilder { .and(isPublic[MethodDescription]) .and(isStatic[MethodDescription]) .and(takesArguments(3)), - classOf[SendCommandAdvice]) + classOf[SendCommandAdvice] + ) /** * For Jedis 4.x. This advice ensures we get the right command name in the Span. Notice @@ -79,8 +80,8 @@ class JedisInstrumentation extends InstrumentationBuilder { .and(isPublic[MethodDescription]) .and(isStatic[MethodDescription]) .and(takesArguments(2)), - classOf[SendCommandAdviceForJedis4]) - + classOf[SendCommandAdviceForJedis4] + ) } @@ -92,7 +93,7 @@ object ClientOperationsAdvice { @static def enter(@Advice.Origin("#m") methodName: String): Scope = { val currentContext = Kamon.currentContext() - if(currentContext.getTag(plain(currentRedisOperationKey)) == null) { + if (currentContext.getTag(plain(currentRedisOperationKey)) == null) { // The actual span name is going to be set in the SendCommand advice val clientSpan = Kamon @@ -102,14 +103,13 @@ object ClientOperationsAdvice { Kamon.storeContext(currentContext .withEntry(Span.Key, clientSpan) - .withTag(currentRedisOperationKey, methodName) - ) + .withTag(currentRedisOperationKey, methodName)) } else Scope.Empty } @Advice.OnMethodExit(onThrowable = classOf[Throwable], suppress = classOf[Throwable]) @static def exit(@Advice.Enter scope: Scope, @Advice.Thrown t: Throwable): Unit = { - if(scope != Scope.Empty) { + if (scope != Scope.Empty) { val span = scope.context.get(Span.Key) if (t != null) { span.fail(t) @@ -148,4 +148,3 @@ object SendCommandAdviceForJedis4 { .tag("db.operation", firstArgument.toString()) } } - diff --git a/instrumentation/kamon-redis/src/main/scala/kamon/instrumentation/lettuce/LettuceInstrumentation.scala b/instrumentation/kamon-redis/src/main/scala/kamon/instrumentation/lettuce/LettuceInstrumentation.scala index 964096cc3..008dc77da 100644 --- a/instrumentation/kamon-redis/src/main/scala/kamon/instrumentation/lettuce/LettuceInstrumentation.scala +++ b/instrumentation/kamon-redis/src/main/scala/kamon/instrumentation/lettuce/LettuceInstrumentation.scala @@ -10,8 +10,11 @@ import scala.annotation.static class LettuceInstrumentation extends InstrumentationBuilder { onType("io.lettuce.core.AbstractRedisAsyncCommands") - .advise(method("dispatch") - .and(takesOneArgumentOf("io.lettuce.core.protocol.RedisCommand")), classOf[AsyncCommandAdvice]) + .advise( + method("dispatch") + .and(takesOneArgumentOf("io.lettuce.core.protocol.RedisCommand")), + classOf[AsyncCommandAdvice] + ) } class AsyncCommandAdvice @@ -23,10 +26,12 @@ object AsyncCommandAdvice { .start(); } - @Advice.OnMethodExit(onThrowable = classOf[Throwable],suppress = classOf[Throwable]) - @static def exit(@Advice.Enter span: Span, - @Advice.Thrown t: Throwable, - @Advice.Return asyncCommand: AsyncCommand[_, _, _]) = { + @Advice.OnMethodExit(onThrowable = classOf[Throwable], suppress = classOf[Throwable]) + @static def exit( + @Advice.Enter span: Span, + @Advice.Thrown t: Throwable, + @Advice.Return asyncCommand: AsyncCommand[_, _, _] + ) = { if (t != null) { span.fail(t); } diff --git a/instrumentation/kamon-redis/src/main/scala/kamon/instrumentation/rediscala/RediscalaInstrumentation.scala b/instrumentation/kamon-redis/src/main/scala/kamon/instrumentation/rediscala/RediscalaInstrumentation.scala index 0164b16b5..e276a6651 100644 --- a/instrumentation/kamon-redis/src/main/scala/kamon/instrumentation/rediscala/RediscalaInstrumentation.scala +++ b/instrumentation/kamon-redis/src/main/scala/kamon/instrumentation/rediscala/RediscalaInstrumentation.scala @@ -11,8 +11,14 @@ import scala.concurrent.Future import scala.util.{Failure, Success} class RediscalaInstrumentation extends InstrumentationBuilder { - onTypes("redis.Request", "redis.ActorRequest", "redis.BufferedRequest", - "redis.commands.BLists", "redis.RoundRobinPoolRequest", "ActorRequest") + onTypes( + "redis.Request", + "redis.ActorRequest", + "redis.BufferedRequest", + "redis.commands.BLists", + "redis.RoundRobinPoolRequest", + "ActorRequest" + ) .advise(method("send").and(takesArguments(1)), classOf[RequestInstrumentation]) onTypes("redis.ActorRequest$class") @@ -31,9 +37,7 @@ object RequestInstrumentation { } @Advice.OnMethodExit(onThrowable = classOf[Throwable], suppress = classOf[Throwable]) - @static def exit(@Advice.Enter span: Span, - @Advice.Thrown t: Throwable, - @Advice.Return future: Future[_]) = { + @static def exit(@Advice.Enter span: Span, @Advice.Thrown t: Throwable, @Advice.Return future: Future[_]) = { if (t != null) { span.fail(t); } @@ -62,9 +66,7 @@ object RoundRobinRequestInstrumentation { } @Advice.OnMethodExit(onThrowable = classOf[Throwable], suppress = classOf[Throwable]) - @static def exit(@Advice.Enter span: Span, - @Advice.Thrown t: Throwable, - @Advice.Return future: Future[_]) = { + @static def exit(@Advice.Enter span: Span, @Advice.Thrown t: Throwable, @Advice.Return future: Future[_]) = { println("Exiting round robin") if (t != null) { span.fail(t); @@ -92,9 +94,7 @@ object ActorRequestAdvice { } @Advice.OnMethodExit(onThrowable = classOf[Throwable], suppress = classOf[Throwable]) - @static def exit(@Advice.Enter span: Span, - @Advice.Thrown t: Throwable, - @Advice.Return future: Future[_]) = { + @static def exit(@Advice.Enter span: Span, @Advice.Thrown t: Throwable, @Advice.Return future: Future[_]) = { if (t != null) { span.fail(t); } diff --git a/instrumentation/kamon-redis/src/test/scala/kamon/instrumentation/combined/RedisInstrumentationsSpec.scala b/instrumentation/kamon-redis/src/test/scala/kamon/instrumentation/combined/RedisInstrumentationsSpec.scala index 62e037875..5a1ab684c 100644 --- a/instrumentation/kamon-redis/src/test/scala/kamon/instrumentation/combined/RedisInstrumentationsSpec.scala +++ b/instrumentation/kamon-redis/src/test/scala/kamon/instrumentation/combined/RedisInstrumentationsSpec.scala @@ -1,6 +1,5 @@ package kamon.instrumentation.combined - import io.lettuce.core.{RedisClient => LettuceClient} import kamon.tag.Lookups import kamon.tag.Lookups._ @@ -20,15 +19,14 @@ import java.time.Duration import scala.concurrent.duration.DurationInt import scala.util.control.NonFatal - class RedisInstrumentationsSpec extends AnyWordSpec - with Matchers - with ScalaFutures - with Eventually - with InitAndStopKamonAfterAll - with MetricInspection.Syntax - with OptionValues - with TestSpanReporter { + with Matchers + with ScalaFutures + with Eventually + with InitAndStopKamonAfterAll + with MetricInspection.Syntax + with OptionValues + with TestSpanReporter { private val logger = LoggerFactory.getLogger(classOf[RedisInstrumentationsSpec]) var container: GenericContainer[Nothing] = _ diff --git a/instrumentation/kamon-scala-future/src/main/scala-2.12/kamon/instrumentation/futures/scala/FutureChainingInstrumentation.scala b/instrumentation/kamon-scala-future/src/main/scala-2.12/kamon/instrumentation/futures/scala/FutureChainingInstrumentation.scala index 2274c8987..a73b0a1b3 100644 --- a/instrumentation/kamon-scala-future/src/main/scala-2.12/kamon/instrumentation/futures/scala/FutureChainingInstrumentation.scala +++ b/instrumentation/kamon-scala-future/src/main/scala-2.12/kamon/instrumentation/futures/scala/FutureChainingInstrumentation.scala @@ -88,7 +88,7 @@ object CallbackRunnableRunInstrumentation { def enter(@Advice.This runnable: HasContext with HasTimestamp with InternalState): Scope = { val timestamp = runnable.timestamp val valueContext = runnable.valueBridge().asInstanceOf[HasContext].context - val context = if(valueContext.nonEmpty()) valueContext else runnable.context + val context = if (valueContext.nonEmpty()) valueContext else runnable.context storeCurrentRunnableTimestamp(timestamp) Kamon.storeContext(context) @@ -142,4 +142,4 @@ object CleanContextFromSeedFuture { unitValue.asInstanceOf[HasContext].setContext(Context.Empty) }) } -} \ No newline at end of file +} diff --git a/instrumentation/kamon-scala-future/src/test/scala/kamon/instrumentation/futures/scala/FutureInstrumentationSpec.scala b/instrumentation/kamon-scala-future/src/test/scala/kamon/instrumentation/futures/scala/FutureInstrumentationSpec.scala index c93d275eb..4c631f699 100644 --- a/instrumentation/kamon-scala-future/src/test/scala/kamon/instrumentation/futures/scala/FutureInstrumentationSpec.scala +++ b/instrumentation/kamon-scala-future/src/test/scala/kamon/instrumentation/futures/scala/FutureInstrumentationSpec.scala @@ -62,4 +62,3 @@ class FutureInstrumentationSpec extends AnyWordSpec with Matchers with ScalaFutu } } } - diff --git a/instrumentation/kamon-scalaz-future/src/test/scala/kamon/instrumentation/futures/scalaz/FutureInstrumentationSpec.scala b/instrumentation/kamon-scalaz-future/src/test/scala/kamon/instrumentation/futures/scalaz/FutureInstrumentationSpec.scala index 7b4fd063a..236abfb34 100644 --- a/instrumentation/kamon-scalaz-future/src/test/scala/kamon/instrumentation/futures/scalaz/FutureInstrumentationSpec.scala +++ b/instrumentation/kamon-scalaz-future/src/test/scala/kamon/instrumentation/futures/scalaz/FutureInstrumentationSpec.scala @@ -63,4 +63,3 @@ class FutureInstrumentationSpec extends AnyWordSpec with Matchers with ScalaFutu } } } - diff --git a/instrumentation/kamon-spring/src/main/scala/kamon/instrumentation/spring/client/ClientInstrumentation.scala b/instrumentation/kamon-spring/src/main/scala/kamon/instrumentation/spring/client/ClientInstrumentation.scala index 4941c2b96..b8978dfc5 100644 --- a/instrumentation/kamon-spring/src/main/scala/kamon/instrumentation/spring/client/ClientInstrumentation.scala +++ b/instrumentation/kamon-spring/src/main/scala/kamon/instrumentation/spring/client/ClientInstrumentation.scala @@ -28,7 +28,9 @@ import scala.collection.mutable object ClientInstrumentation { private val instrumentation = HttpClientInstrumentation.from( - Kamon.config().getConfig("kamon.instrumentation.spring.client"), "spring.client") + Kamon.config().getConfig("kamon.instrumentation.spring.client"), + "spring.client" + ) def getHandler(request: ClientRequest): RequestHandler[ClientRequest] = { instrumentation.createHandler(toRequestBuilder(request), Kamon.currentContext()) diff --git a/instrumentation/kamon-spring/src/main/scala/kamon/instrumentation/spring/server/CallableContextWrapper.scala b/instrumentation/kamon-spring/src/main/scala/kamon/instrumentation/spring/server/CallableContextWrapper.scala index 50a2f887f..3b665f788 100644 --- a/instrumentation/kamon-spring/src/main/scala/kamon/instrumentation/spring/server/CallableContextWrapper.scala +++ b/instrumentation/kamon-spring/src/main/scala/kamon/instrumentation/spring/server/CallableContextWrapper.scala @@ -27,7 +27,8 @@ object CallableContextWrapper { override def call(): T = { val scope = Kamon.storeContext(_context) - try { callable.call() } finally { + try { callable.call() } + finally { scope.close() } } diff --git a/instrumentation/kamon-spring/src/main/scala/kamon/instrumentation/spring/server/SpringMVCInstrumentation.scala b/instrumentation/kamon-spring/src/main/scala/kamon/instrumentation/spring/server/SpringMVCInstrumentation.scala index e5e291fdf..3c212ef88 100644 --- a/instrumentation/kamon-spring/src/main/scala/kamon/instrumentation/spring/server/SpringMVCInstrumentation.scala +++ b/instrumentation/kamon-spring/src/main/scala/kamon/instrumentation/spring/server/SpringMVCInstrumentation.scala @@ -48,14 +48,18 @@ class SpringMVCInstrumentation extends InstrumentationBuilder { onType("org.springframework.web.context.request.async.WebAsyncManager") .advise( method("startCallableProcessing") - .and(withArgument(0, classOf[Callable[_]])), classOf[CallableWrapper]) + .and(withArgument(0, classOf[Callable[_]])), + classOf[CallableWrapper] + ) } class DispatchAdvice object DispatchAdvice { @Advice.OnMethodEnter() - @static def enter(@Advice.This dispatcherServlet: HasServerInstrumentation, - @Advice.Argument(0) request: HttpServletRequest): (RequestHandler, Scope) = { + @static def enter( + @Advice.This dispatcherServlet: HasServerInstrumentation, + @Advice.Argument(0) request: HttpServletRequest + ): (RequestHandler, Scope) = { val requestHandler = Option(request.getAttribute("kamon-handler").asInstanceOf[RequestHandler]) .getOrElse({ val serverInstrumentation = dispatcherServlet.getServerInstrumentation(request) @@ -70,9 +74,11 @@ object DispatchAdvice { } @Advice.OnMethodExit(onThrowable = classOf[Throwable], suppress = classOf[Throwable]) - @static def exit(@Advice.Enter enter: (RequestHandler, Scope), - @Advice.Argument(0) request: HttpServletRequest, - @Advice.Argument(1) response: HttpServletResponse): Unit = { + @static def exit( + @Advice.Enter enter: (RequestHandler, Scope), + @Advice.Argument(0) request: HttpServletRequest, + @Advice.Argument(1) response: HttpServletResponse + ): Unit = { val (handler, scope) = enter if (response.isCommitted) { diff --git a/instrumentation/kamon-spring/src/test/scala/kamon.instrumentation/SpringClientInstrumentationSpec.scala b/instrumentation/kamon-spring/src/test/scala/kamon.instrumentation/SpringClientInstrumentationSpec.scala index c22e5447e..0cf26f21d 100644 --- a/instrumentation/kamon-spring/src/test/scala/kamon.instrumentation/SpringClientInstrumentationSpec.scala +++ b/instrumentation/kamon-spring/src/test/scala/kamon.instrumentation/SpringClientInstrumentationSpec.scala @@ -12,7 +12,7 @@ import testapp.TestApp import scala.concurrent.duration.DurationInt class SpringClientInstrumentationSpec - extends AnyWordSpec + extends AnyWordSpec with Matchers with InitAndStopKamonAfterAll with TestSpanReporter { @@ -25,7 +25,6 @@ class SpringClientInstrumentationSpec TestApp.main(Array(port)) } - "WebClient instrumentation" should { "add a traceID to outgoing request" in { val traceID = WebClient.create(baseUrl + "traceID").get() diff --git a/instrumentation/kamon-spring/src/test/scala/kamon.instrumentation/SpringMVCInstrumentationSpec.scala b/instrumentation/kamon-spring/src/test/scala/kamon.instrumentation/SpringMVCInstrumentationSpec.scala index 2fd749e01..87dadf5ea 100644 --- a/instrumentation/kamon-spring/src/test/scala/kamon.instrumentation/SpringMVCInstrumentationSpec.scala +++ b/instrumentation/kamon-spring/src/test/scala/kamon.instrumentation/SpringMVCInstrumentationSpec.scala @@ -14,7 +14,7 @@ import scala.concurrent.duration.DurationInt import scala.util.Try class SpringMVCInstrumentationSpec - extends AnyWordSpec + extends AnyWordSpec with Matchers with InitAndStopKamonAfterAll with TestSpanReporter { @@ -82,8 +82,7 @@ class SpringMVCInstrumentationSpec val request = new Request.Builder() .url(url) .post(RequestBody - .create(MediaType.get("application/json; charset=utf-8"), - """{"name": "Simone", "role": "Dev"}""")) + .create(MediaType.get("application/json; charset=utf-8"), """{"name": "Simone", "role": "Dev"}""")) .build Try(client.newCall(request).execute) diff --git a/instrumentation/kamon-system-metrics/src/main/scala/kamon/instrumentation/system/host/HostMetrics.scala b/instrumentation/kamon-system-metrics/src/main/scala/kamon/instrumentation/system/host/HostMetrics.scala index 53a441a7b..e5f2f2854 100644 --- a/instrumentation/kamon-system-metrics/src/main/scala/kamon/instrumentation/system/host/HostMetrics.scala +++ b/instrumentation/kamon-system-metrics/src/main/scala/kamon/instrumentation/system/host/HostMetrics.scala @@ -199,16 +199,18 @@ object HostMetrics { private val _mountsCache = mutable.Map.empty[String, MountInstruments] def mountInstruments(mountName: String): MountInstruments = - _mountsCache.getOrElseUpdate(mountName, { - val mount = TagSet.of("mount", mountName) - - MountInstruments( - register(FileSystemMountSpaceUsed, mount), - register(FileSystemMountSpaceUsage, mount), - register(FileSystemMountSpaceFree, mount), - register(FileSystemMountSpaceTotal, mount) - ) - }) + _mountsCache.getOrElseUpdate( + mountName, { + val mount = TagSet.of("mount", mountName) + + MountInstruments( + register(FileSystemMountSpaceUsed, mount), + register(FileSystemMountSpaceUsage, mount), + register(FileSystemMountSpaceFree, mount), + register(FileSystemMountSpaceTotal, mount) + ) + } + ) } object StorageMountInstruments { @@ -228,16 +230,18 @@ object HostMetrics { private val _deviceInstrumentsCache = mutable.Map.empty[String, DeviceInstruments] def deviceInstruments(deviceName: String): DeviceInstruments = - _deviceInstrumentsCache.getOrElseUpdate(deviceName, { - val device = TagSet.of("device", deviceName) - - DeviceInstruments( - DiffCounter(register(StorageDeviceReadOps, device)), - DiffCounter(register(StorageDeviceRead, device)), - DiffCounter(register(StorageDeviceWriteOps, device)), - DiffCounter(register(StorageDeviceWrite, device)) - ) - }) + _deviceInstrumentsCache.getOrElseUpdate( + deviceName, { + val device = TagSet.of("device", deviceName) + + DeviceInstruments( + DiffCounter(register(StorageDeviceReadOps, device)), + DiffCounter(register(StorageDeviceRead, device)), + DiffCounter(register(StorageDeviceWriteOps, device)), + DiffCounter(register(StorageDeviceWrite, device)) + ) + } + ) } object StorageDeviceInstruments { @@ -257,18 +261,20 @@ object HostMetrics { private val _interfaceCache = mutable.Map.empty[String, InterfaceInstruments] def interfaceInstruments(interfaceName: String): InterfaceInstruments = - _interfaceCache.getOrElseUpdate(interfaceName, { - val interface = TagSet.of("interface", interfaceName) - - InterfaceInstruments( - DiffCounter(register(NetworkDataRead, interface)), - DiffCounter(register(NetworkPacketsRead, interface)), - DiffCounter(register(NetworkPacketsReadFailed, interface)), - DiffCounter(register(NetworkDataWrite, interface)), - DiffCounter(register(NetworkPacketsWrite, interface)), - DiffCounter(register(NetworkPacketsWriteFailed, interface)) - ) - }) + _interfaceCache.getOrElseUpdate( + interfaceName, { + val interface = TagSet.of("interface", interfaceName) + + InterfaceInstruments( + DiffCounter(register(NetworkDataRead, interface)), + DiffCounter(register(NetworkPacketsRead, interface)), + DiffCounter(register(NetworkPacketsReadFailed, interface)), + DiffCounter(register(NetworkDataWrite, interface)), + DiffCounter(register(NetworkPacketsWrite, interface)), + DiffCounter(register(NetworkPacketsWriteFailed, interface)) + ) + } + ) } object NetworkActivityInstruments { @@ -281,6 +287,7 @@ object HostMetrics { sendErrorPackets: DiffCounter ) } + /** * A modified Counter that keeps track of a monotonically increasing value and only records the difference between * the current and previous value on the target counter. diff --git a/instrumentation/kamon-system-metrics/src/main/scala/kamon/instrumentation/system/host/HostMetricsCollector.scala b/instrumentation/kamon-system-metrics/src/main/scala/kamon/instrumentation/system/host/HostMetricsCollector.scala index b215998a1..9c75e63df 100644 --- a/instrumentation/kamon-system-metrics/src/main/scala/kamon/instrumentation/system/host/HostMetricsCollector.scala +++ b/instrumentation/kamon-system-metrics/src/main/scala/kamon/instrumentation/system/host/HostMetricsCollector.scala @@ -45,11 +45,10 @@ class HostMetricsCollector(ec: ExecutionContext) extends ScheduledAction { private val _frequentCollector = new FrequentCollectionTask private val _infrequentCollector = new InfrequentCollectionTask - override def run(): Unit = { _frequentCollector.run() - if(Duration.between(_lastInfrequentTick, Instant.now()).getSeconds() >= 10) { + if (Duration.between(_lastInfrequentTick, Instant.now()).getSeconds() >= 10) { _infrequentCollector.run() _lastInfrequentTick = Instant.now() } @@ -107,7 +106,7 @@ class HostMetricsCollector(ec: ExecutionContext) extends ScheduledAction { val steal = ticksDiff(previousTicks, currentTicks, TickType.STEAL) val total = user + nice + system + idle + iowait + irq + softirq + steal - def toPercent(value: Long): Long = ((100D * value.toDouble) / total.toDouble).toLong + def toPercent(value: Long): Long = ((100d * value.toDouble) / total.toDouble).toLong _cpuInstruments.user.record(toPercent(user)) _cpuInstruments.system.record(toPercent(system)) @@ -179,9 +178,9 @@ class HostMetricsCollector(ec: ExecutionContext) extends ScheduledAction { private def recordLoadAverage(): Unit = { val loadAverage = _hal.getProcessor.getSystemLoadAverage(3) - if (loadAverage(0) >= 0D) _loadAverageInstruments.oneMinute.update(loadAverage(0)) - if (loadAverage(1) >= 0D) _loadAverageInstruments.fiveMinutes.update(loadAverage(1)) - if (loadAverage(2) >= 0D) _loadAverageInstruments.fifteenMinutes.update(loadAverage(2)) + if (loadAverage(0) >= 0d) _loadAverageInstruments.oneMinute.update(loadAverage(0)) + if (loadAverage(1) >= 0d) _loadAverageInstruments.fiveMinutes.update(loadAverage(1)) + if (loadAverage(2) >= 0d) _loadAverageInstruments.fifteenMinutes.update(loadAverage(2)) } private def recordStorageUsage(): Unit = { @@ -201,7 +200,7 @@ class HostMetricsCollector(ec: ExecutionContext) extends ScheduledAction { }) } - private def toPercent(value: Long, total: Long): Long = ((100D * value.toDouble) / total.toDouble).toLong + private def toPercent(value: Long, total: Long): Long = ((100d * value.toDouble) / total.toDouble).toLong private def recordStorageActivity(): Unit = { val devices = _hal.getDiskStores diff --git a/instrumentation/kamon-system-metrics/src/main/scala/kamon/instrumentation/system/jvm/JvmMetrics.scala b/instrumentation/kamon-system-metrics/src/main/scala/kamon/instrumentation/system/jvm/JvmMetrics.scala index a7a7b5ce2..1047e29e4 100644 --- a/instrumentation/kamon-system-metrics/src/main/scala/kamon/instrumentation/system/jvm/JvmMetrics.scala +++ b/instrumentation/kamon-system-metrics/src/main/scala/kamon/instrumentation/system/jvm/JvmMetrics.scala @@ -18,7 +18,10 @@ package kamon.instrumentation.system.jvm import java.lang.management.ManagementFactory import kamon.Kamon -import kamon.instrumentation.system.jvm.JvmMetrics.MemoryUsageInstruments.{BufferPoolInstruments, MemoryRegionInstruments} +import kamon.instrumentation.system.jvm.JvmMetrics.MemoryUsageInstruments.{ + BufferPoolInstruments, + MemoryRegionInstruments +} import kamon.instrumentation.system.jvm.JvmMetricsCollector.{Collector, MemoryPool, ThreadState} import kamon.metric.{Gauge, Histogram, InstrumentGroup, MeasurementUnit} import kamon.tag.TagSet @@ -113,7 +116,7 @@ object JvmMetrics { name = "jvm.threads.daemon", description = "Tracks the current number of daemon threads on the JVM" ) - + val ThreadsStates = Kamon.gauge( name = "jvm.threads.states", description = "Tracks the current number of threads on each possible state" @@ -158,14 +161,16 @@ object JvmMetrics { val promotionToOld = register(GcPromotion, "space", "old") def garbageCollectionTime(collector: Collector): Histogram = - _collectorCache.getOrElseUpdate(collector.alias, { - val collectorTags = TagSet.builder() - .add("collector", collector.alias) - .add("generation", collector.generation.toString) - .build() - - register(GC, collectorTags) - }) + _collectorCache.getOrElseUpdate( + collector.alias, { + val collectorTags = TagSet.builder() + .add("collector", collector.alias) + .add("generation", collector.generation.toString) + .build() + + register(GC, collectorTags) + } + ) } class MemoryUsageInstruments(tags: TagSet) extends InstrumentGroup(tags) { @@ -176,40 +181,46 @@ object JvmMetrics { private val _memoryBuffersCache = mutable.Map.empty[String, BufferPoolInstruments] def regionInstruments(regionName: String): MemoryRegionInstruments = - _memoryRegionsCache.getOrElseUpdate(regionName, { - val region = TagSet.of("region", regionName) - - MemoryRegionInstruments( - register(MemoryUsed, region), - register(MemoryFree, region), - register(MemoryCommitted, region), - register(MemoryMax, region) - ) - }) + _memoryRegionsCache.getOrElseUpdate( + regionName, { + val region = TagSet.of("region", regionName) + + MemoryRegionInstruments( + register(MemoryUsed, region), + register(MemoryFree, region), + register(MemoryCommitted, region), + register(MemoryMax, region) + ) + } + ) def poolInstruments(pool: MemoryPool): MemoryRegionInstruments = - _memoryPoolsCache.getOrElseUpdate(pool.alias, { - val region = TagSet.of("pool", pool.alias) - - MemoryRegionInstruments( - register(MemoryPoolUsed, region), - register(MemoryPoolFree, region), - register(MemoryPoolCommitted, region), - register(MemoryPoolMax, region) - ) - }) + _memoryPoolsCache.getOrElseUpdate( + pool.alias, { + val region = TagSet.of("pool", pool.alias) + + MemoryRegionInstruments( + register(MemoryPoolUsed, region), + register(MemoryPoolFree, region), + register(MemoryPoolCommitted, region), + register(MemoryPoolMax, region) + ) + } + ) def bufferPoolInstruments(poolName: String): BufferPoolInstruments = { - _memoryBuffersCache.getOrElseUpdate(poolName, { - val bufferTags = tags - .withTag("pool", poolName) - - BufferPoolInstruments( - register(BufferPoolCount, bufferTags), - register(BufferPoolUsed, bufferTags), - register(BufferPoolCapacity, bufferTags) - ) - }) + _memoryBuffersCache.getOrElseUpdate( + poolName, { + val bufferTags = tags + .withTag("pool", poolName) + + BufferPoolInstruments( + register(BufferPoolCount, bufferTags), + register(BufferPoolUsed, bufferTags), + register(BufferPoolCapacity, bufferTags) + ) + } + ) } } @@ -224,30 +235,30 @@ object JvmMetrics { val total = register(ThreadsTotal) val peak = register(ThreadsPeak) val daemon = register(ThreadsDaemon) - + def threadState(threadState: ThreadState): Gauge = { - _threadsStatesCache.getOrElseUpdate(threadState, { - val stateTag = TagSet.of("state", threadState.toString) - - register(ThreadsStates, stateTag) - }) + _threadsStatesCache.getOrElseUpdate( + threadState, { + val stateTag = TagSet.of("state", threadState.toString) + + register(ThreadsStates, stateTag) + } + ) } } object MemoryUsageInstruments { - case class MemoryRegionInstruments ( + case class MemoryRegionInstruments( used: Histogram, free: Histogram, committed: Gauge, max: Gauge ) - case class BufferPoolInstruments ( + case class BufferPoolInstruments( count: Gauge, used: Gauge, capacity: Gauge ) } } - - diff --git a/instrumentation/kamon-system-metrics/src/main/scala/kamon/instrumentation/system/jvm/JvmMetricsCollector.scala b/instrumentation/kamon-system-metrics/src/main/scala/kamon/instrumentation/system/jvm/JvmMetricsCollector.scala index 6280cc887..e042271f8 100644 --- a/instrumentation/kamon-system-metrics/src/main/scala/kamon/instrumentation/system/jvm/JvmMetricsCollector.scala +++ b/instrumentation/kamon-system-metrics/src/main/scala/kamon/instrumentation/system/jvm/JvmMetricsCollector.scala @@ -24,7 +24,12 @@ import com.typesafe.config.Config import javax.management.openmbean.CompositeData import javax.management.{Notification, NotificationEmitter, NotificationListener} -import kamon.instrumentation.system.jvm.JvmMetrics.{ClassLoadingInstruments, GarbageCollectionInstruments, MemoryUsageInstruments, ThreadsInstruments} +import kamon.instrumentation.system.jvm.JvmMetrics.{ + ClassLoadingInstruments, + GarbageCollectionInstruments, + MemoryUsageInstruments, + ThreadsInstruments +} import kamon.instrumentation.system.jvm.JvmMetricsCollector.{Collector, MemoryPool, ThreadState} import kamon.module.{Module, ModuleFactory, ScheduledAction} import kamon.tag.TagSet @@ -40,7 +45,8 @@ class JvmMetricsCollector(ec: ExecutionContext) extends ScheduledAction { private val _memoryUsageInstruments = new MemoryUsageInstruments(_defaultTags) private val _threadsUsageInstruments = new ThreadsInstruments() private val _classLoadingInstruments = new ClassLoadingInstruments(_defaultTags) - private val _jmxCollectorTask = new JmxMetricsCollectorTask(_memoryUsageInstruments, _threadsUsageInstruments, _classLoadingInstruments) + private val _jmxCollectorTask = + new JmxMetricsCollectorTask(_memoryUsageInstruments, _threadsUsageInstruments, _classLoadingInstruments) override def run(): Unit = { _jmxCollectorTask.run() @@ -57,7 +63,7 @@ class JvmMetricsCollector(ec: ExecutionContext) extends ScheduledAction { val gcListener = new GcNotificationListener(gcInstruments) ManagementFactory.getGarbageCollectorMXBeans().asScala.foreach(gcBean => { - if(gcBean.isInstanceOf[NotificationEmitter]) + if (gcBean.isInstanceOf[NotificationEmitter]) gcBean.asInstanceOf[NotificationEmitter].addNotificationListener(gcListener, null, null) }) @@ -66,7 +72,7 @@ class JvmMetricsCollector(ec: ExecutionContext) extends ScheduledAction { private def deregisterGcListener(): Unit = { ManagementFactory.getGarbageCollectorMXBeans().asScala.foreach(gcBean => { - if(gcBean.isInstanceOf[NotificationEmitter]) { + if (gcBean.isInstanceOf[NotificationEmitter]) { gcBean.asInstanceOf[NotificationEmitter].removeNotificationListener(_gcListener) } }) @@ -74,13 +80,13 @@ class JvmMetricsCollector(ec: ExecutionContext) extends ScheduledAction { class GcNotificationListener(val gcInstruments: GarbageCollectionInstruments) extends NotificationListener { override def handleNotification(notification: Notification, handback: Any): Unit = { - if(notification.getType() == GARBAGE_COLLECTION_NOTIFICATION) { + if (notification.getType() == GARBAGE_COLLECTION_NOTIFICATION) { val compositeData = notification.getUserData.asInstanceOf[CompositeData] val info = GarbageCollectionNotificationInfo.from(compositeData) val collector = Collector.find(info.getGcName) // This prevents recording the ZGC/Shenandoah cycles - if(collector.pausesTheJVM) { + if (collector.pausesTheJVM) { gcInstruments.garbageCollectionTime(collector).record(info.getGcInfo.getDuration) } @@ -93,11 +99,11 @@ class JvmMetricsCollector(ec: ExecutionContext) extends ScheduledAction { // We assume that if the old generation grew during this GC event then some data was promoted to it and will // record it as promotion to the old generation. - if(region.usage == MemoryPool.Usage.OldGeneration) { + if (region.usage == MemoryPool.Usage.OldGeneration) { val regionUsageAfterGc = usageAfterGc(regionName) val diff = regionUsageAfterGc.getUsed - regionUsageBeforeGc.getUsed - if(diff > 0) + if (diff > 0) gcInstruments.promotionToOld.record(diff) } @@ -109,22 +115,27 @@ class JvmMetricsCollector(ec: ExecutionContext) extends ScheduledAction { case (regionName, regionUsageAfterGC) => val region = MemoryPool.find(regionName) - if(regionUsageAfterGC.getMax != -1 && (region.usage == MemoryPool.Usage.OldGeneration || region.usage == MemoryPool.Usage.SingleGeneration)) { + if ( + regionUsageAfterGC.getMax != -1 && (region.usage == MemoryPool.Usage.OldGeneration || region.usage == MemoryPool.Usage.SingleGeneration) + ) { totalMemory += regionUsageAfterGC.getMax usedMemory += regionUsageAfterGC.getUsed } } - if(totalMemory > 0L) { - val utilizationPercentage = Math.min(100D, (usedMemory.toDouble * 100D) / totalMemory.toDouble).toLong + if (totalMemory > 0L) { + val utilizationPercentage = Math.min(100d, (usedMemory.toDouble * 100d) / totalMemory.toDouble).toLong gcInstruments.memoryUtilization.record(utilizationPercentage) } } } } - class JmxMetricsCollectorTask(memoryUsageInstruments: MemoryUsageInstruments, threadsInstruments: ThreadsInstruments, classLoadingInstruments: ClassLoadingInstruments) - extends Runnable { + class JmxMetricsCollectorTask( + memoryUsageInstruments: MemoryUsageInstruments, + threadsInstruments: ThreadsInstruments, + classLoadingInstruments: ClassLoadingInstruments + ) extends Runnable { private val _heapUsage = memoryUsageInstruments.regionInstruments("heap") private val _nonHeapUsage = memoryUsageInstruments.regionInstruments("non-heap") @@ -141,28 +152,27 @@ class JvmMetricsCollector(ec: ExecutionContext) extends ScheduledAction { allThreadIds.map(threadsMxBean.getThreadInfo(_, 0)) .groupBy(_.getThreadState) .mapValues(_.length) - .foreach { - case (state, count) => + .foreach { + case (state, count) => val threadState = ThreadState.find(state.toString) - threadsInstruments.threadState(threadState).update(count) + threadsInstruments.threadState(threadState).update(count) } val totalAllocatedBytes = threadsMxBean.getThreadAllocatedBytes(allThreadIds).sum val bytesAllocatedSinceLastCheck = totalAllocatedBytes - _lastSeenAllocatedBytes - if(bytesAllocatedSinceLastCheck > 0) + if (bytesAllocatedSinceLastCheck > 0) memoryUsageInstruments.allocation.increment(bytesAllocatedSinceLastCheck) _lastSeenAllocatedBytes = totalAllocatedBytes - val currentHeapUsage = ManagementFactory.getMemoryMXBean.getHeapMemoryUsage - val freeHeap = Math.max(0L, currentHeapUsage.getMax - currentHeapUsage.getUsed) + val freeHeap = Math.max(0L, currentHeapUsage.getMax - currentHeapUsage.getUsed) _heapUsage.free.record(freeHeap) _heapUsage.used.record(currentHeapUsage.getUsed) _heapUsage.max.update(currentHeapUsage.getMax) _heapUsage.committed.update(currentHeapUsage.getCommitted) val currentNonHeapUsage = ManagementFactory.getMemoryMXBean.getNonHeapMemoryUsage - val freeNonHeap = Math.max(0L, currentNonHeapUsage.getMax - currentNonHeapUsage.getUsed) + val freeNonHeap = Math.max(0L, currentNonHeapUsage.getMax - currentNonHeapUsage.getUsed) _nonHeapUsage.free.record(freeNonHeap) _nonHeapUsage.used.record(currentNonHeapUsage.getUsed) _nonHeapUsage.max.update(currentNonHeapUsage.getMax) @@ -176,7 +186,7 @@ class JvmMetricsCollector(ec: ExecutionContext) extends ScheduledAction { ManagementFactory.getMemoryPoolMXBeans.asScala.foreach(memoryBean => { val poolInstruments = memoryUsageInstruments.poolInstruments(MemoryPool.find(memoryBean.getName)) val memoryUsage = memoryBean.getUsage - val freeMemory = Math.max(0L, memoryUsage.getMax - memoryUsage.getUsed) + val freeMemory = Math.max(0L, memoryUsage.getMax - memoryUsage.getUsed) poolInstruments.free.record(freeMemory) poolInstruments.used.record(memoryUsage.getUsed) @@ -186,7 +196,8 @@ class JvmMetricsCollector(ec: ExecutionContext) extends ScheduledAction { ManagementFactory.getPlatformMXBeans(classOf[BufferPoolMXBean]).asScala.toList.map { bean => val bufferPoolInstruments = memoryUsageInstruments.bufferPoolInstruments( - MemoryPool.sanitize(bean.getName)) + MemoryPool.sanitize(bean.getName) + ) bufferPoolInstruments.count.update(bean.getCount) bufferPoolInstruments.used.update(bean.getMemoryUsed) @@ -203,7 +214,7 @@ object JvmMetricsCollector { new JvmMetricsCollector(settings.executionContext) } - case class Collector ( + case class Collector( name: String, alias: String, generation: Collector.Generation, @@ -221,30 +232,30 @@ object JvmMetricsCollector { } def find(collectorName: String): Collector = - _collectorMappings.get(collectorName).getOrElse ( + _collectorMappings.get(collectorName).getOrElse( Collector(collectorName, sanitizeCollectorName(collectorName), Collector.Generation.Unknown) ) - private val _collectorMappings: Map[String, Collector] = Map ( - "Copy" -> Collector("Copy", "copy", Generation.Young), - "ParNew" -> Collector("ParNew", "par-new", Generation.Young), - "MarkSweepCompact" -> Collector("MarkSweepCompact", "mark-sweep-compact", Generation.Old), + private val _collectorMappings: Map[String, Collector] = Map( + "Copy" -> Collector("Copy", "copy", Generation.Young), + "ParNew" -> Collector("ParNew", "par-new", Generation.Young), + "MarkSweepCompact" -> Collector("MarkSweepCompact", "mark-sweep-compact", Generation.Old), "ConcurrentMarkSweep" -> Collector("ConcurrentMarkSweep", "concurrent-mark-sweep", Generation.Old), - "PS Scavenge" -> Collector("PS Scavenge", "ps-scavenge", Generation.Young), - "PS MarkSweep" -> Collector("PS MarkSweep", "ps-mark-sweep", Generation.Old), + "PS Scavenge" -> Collector("PS Scavenge", "ps-scavenge", Generation.Young), + "PS MarkSweep" -> Collector("PS MarkSweep", "ps-mark-sweep", Generation.Old), "G1 Young Generation" -> Collector("G1 Young Generation", "g1-young", Generation.Young), - "G1 Old Generation" -> Collector("G1 Old Generation", "g1-old", Generation.Old), - "ZGC Pauses" -> Collector("ZGC Pauses", "zgc-pauses", Generation.Single), - "ZGC Cycles" -> Collector("ZGC Cycles", "zgc-cycles", Generation.Single, false), - "Shenandoah Pauses" -> Collector("Shenandoah Pauses", "shenandoah-pauses", Generation.Single), - "Shenandoah Cycles" -> Collector("Shenandoah Cycles", "shenandoah-cycles", Generation.Single, false) + "G1 Old Generation" -> Collector("G1 Old Generation", "g1-old", Generation.Old), + "ZGC Pauses" -> Collector("ZGC Pauses", "zgc-pauses", Generation.Single), + "ZGC Cycles" -> Collector("ZGC Cycles", "zgc-cycles", Generation.Single, false), + "Shenandoah Pauses" -> Collector("Shenandoah Pauses", "shenandoah-pauses", Generation.Single), + "Shenandoah Cycles" -> Collector("Shenandoah Cycles", "shenandoah-cycles", Generation.Single, false) ) private def sanitizeCollectorName(name: String): String = name.replaceAll("""[^\w]""", "-").toLowerCase } - case class MemoryPool ( + case class MemoryPool( name: String, alias: String, usage: MemoryPool.Usage @@ -280,20 +291,24 @@ object JvmMetricsCollector { } private val _memoryRegionMappings: TrieMap[String, MemoryPool] = TrieMap( - "Metaspace" -> MemoryPool("Metaspace", "metaspace", Usage.Metaspace), - "Code Cache" -> MemoryPool("Code Cache", "code-cache", Usage.CodeCache), - "CodeHeap 'profiled nmethods'" -> MemoryPool("Code Heap", "code-heap-profiled-nmethods", Usage.CodeCache), - "CodeHeap 'non-profiled nmethods'" -> MemoryPool("Code Cache", "code-heap-non-profiled-nmethods", Usage.CodeCache), - "CodeHeap 'non-nmethods'" -> MemoryPool("Code Cache", "code-heap-non-nmethods", Usage.CodeCache), - "Compressed Class Space" -> MemoryPool("Compressed Class Space", "compressed-class-space", Usage.CodeCache), - "Eden Space" -> MemoryPool("Eden Space", "eden", Usage.Eden), - "PS Eden Space" -> MemoryPool("PS Eden Space", "eden", Usage.Eden), - "PS Survivor Space" -> MemoryPool("PS Survivor Space", "survivor", Usage.YoungGeneration), - "PS Old Gen" -> MemoryPool("PS Old Gen", "old", Usage.OldGeneration), - "Survivor Space" -> MemoryPool("Survivor Space", "survivor-space", Usage.YoungGeneration), - "Tenured Gen" -> MemoryPool("Tenured Gen", "tenured-gen", Usage.OldGeneration), - "ZHeap" -> MemoryPool("ZGZ Heap", "zheap", Usage.SingleGeneration), - "Shenandoah" -> MemoryPool("ZGZ Heap", "shenandoah", Usage.SingleGeneration) + "Metaspace" -> MemoryPool("Metaspace", "metaspace", Usage.Metaspace), + "Code Cache" -> MemoryPool("Code Cache", "code-cache", Usage.CodeCache), + "CodeHeap 'profiled nmethods'" -> MemoryPool("Code Heap", "code-heap-profiled-nmethods", Usage.CodeCache), + "CodeHeap 'non-profiled nmethods'" -> MemoryPool( + "Code Cache", + "code-heap-non-profiled-nmethods", + Usage.CodeCache + ), + "CodeHeap 'non-nmethods'" -> MemoryPool("Code Cache", "code-heap-non-nmethods", Usage.CodeCache), + "Compressed Class Space" -> MemoryPool("Compressed Class Space", "compressed-class-space", Usage.CodeCache), + "Eden Space" -> MemoryPool("Eden Space", "eden", Usage.Eden), + "PS Eden Space" -> MemoryPool("PS Eden Space", "eden", Usage.Eden), + "PS Survivor Space" -> MemoryPool("PS Survivor Space", "survivor", Usage.YoungGeneration), + "PS Old Gen" -> MemoryPool("PS Old Gen", "old", Usage.OldGeneration), + "Survivor Space" -> MemoryPool("Survivor Space", "survivor-space", Usage.YoungGeneration), + "Tenured Gen" -> MemoryPool("Tenured Gen", "tenured-gen", Usage.OldGeneration), + "ZHeap" -> MemoryPool("ZGZ Heap", "zheap", Usage.SingleGeneration), + "Shenandoah" -> MemoryPool("ZGZ Heap", "shenandoah", Usage.SingleGeneration) ) private val _invalidChars: Regex = """[^a-z0-9]""".r @@ -301,27 +316,27 @@ object JvmMetricsCollector { def sanitize(name: String): String = _invalidChars.replaceAllIn(name.toLowerCase, "-") } - + sealed trait ThreadState object ThreadState { - case object New extends ThreadState { override def toString: String = "new"} + case object New extends ThreadState { override def toString: String = "new" } case object Runnable extends ThreadState { override def toString: String = "runnable" } case object Blocked extends ThreadState { override def toString: String = "blocked" } case object Waiting extends ThreadState { override def toString: String = "waiting" } case object TimedWaiting extends ThreadState { override def toString: String = "timed-waiting" } case object Terminated extends ThreadState { override def toString: String = "terminated" } case object Unknown extends ThreadState { override def toString: String = "unknown" } - + def find(state: String): ThreadState = _threadStateMapping.getOrElse(state, Unknown) - + private val _threadStateMapping: Map[String, ThreadState] = Map( - "NEW" -> New, - "RUNNABLE" -> Runnable, - "BLOCKED" -> Blocked, - "WAITING" -> Waiting, + "NEW" -> New, + "RUNNABLE" -> Runnable, + "BLOCKED" -> Blocked, + "WAITING" -> Waiting, "TIMED_WAITING" -> TimedWaiting, - "TERMINATED" -> Terminated + "TERMINATED" -> Terminated ) } } diff --git a/instrumentation/kamon-system-metrics/src/main/scala/kamon/instrumentation/system/process/ProcessMetrics.scala b/instrumentation/kamon-system-metrics/src/main/scala/kamon/instrumentation/system/process/ProcessMetrics.scala index b2f6f9dea..69a03003e 100644 --- a/instrumentation/kamon-system-metrics/src/main/scala/kamon/instrumentation/system/process/ProcessMetrics.scala +++ b/instrumentation/kamon-system-metrics/src/main/scala/kamon/instrumentation/system/process/ProcessMetrics.scala @@ -28,21 +28,20 @@ object ProcessMetrics { unit = MeasurementUnit.percentage ) - val ULimitMaxFileDescriptors = Kamon.gauge ( + val ULimitMaxFileDescriptors = Kamon.gauge( name = "process.ulimit.file-descriptors.max", description = "Tracks the max number of file descriptors that can be used by the process" ) - val ULimitUsedFileDescriptors = Kamon.gauge ( + val ULimitUsedFileDescriptors = Kamon.gauge( name = "process.ulimit.file-descriptors.used", description = "Tracks the number of file descriptors used by the process" ) - val Hiccups = Kamon.timer ( + val Hiccups = Kamon.timer( name = "process.hiccups", description = "Tracks the process hiccups generated by either garbage collection or OS noise" ) - class ProcessInstruments(tags: TagSet) extends InstrumentGroup(tags) { val user = register(ProcessCpu, "mode", "user") val system = register(ProcessCpu, "mode", "system") diff --git a/instrumentation/kamon-system-metrics/src/main/scala/kamon/instrumentation/system/process/ProcessMetricsCollector.scala b/instrumentation/kamon-system-metrics/src/main/scala/kamon/instrumentation/system/process/ProcessMetricsCollector.scala index 0c02a68cf..32cb0f0b8 100644 --- a/instrumentation/kamon-system-metrics/src/main/scala/kamon/instrumentation/system/process/ProcessMetricsCollector.scala +++ b/instrumentation/kamon-system-metrics/src/main/scala/kamon/instrumentation/system/process/ProcessMetricsCollector.scala @@ -39,7 +39,6 @@ class ProcessMetricsCollector(ec: ExecutionContext) extends ScheduledAction { private val _collectionTask = new MetricsCollectionTask private val _hiccupMonitor = startHiccupMonitor() - override def run(): Unit = { _collectionTask.run() } @@ -81,18 +80,18 @@ class ProcessMetricsCollector(ec: ExecutionContext) extends ScheduledAction { private def recordProcessCpu(): Unit = { val process = _os.getProcess(_pid) val previous = _previousProcessCpuTime - val current = Array ( + val current = Array( process.getKernelTime(), process.getUserTime(), process.getUpTime() ) - if(previous.nonEmpty) { + if (previous.nonEmpty) { val kernelTime = math.max(0L, current(0) - previous(0)) val userTime = math.max(0L, current(1) - previous(1)) val totalTime = math.max(0L, current(2) - previous(2)) def toPercent(value: Long): Long = { - if(totalTime > 0) ((100D * value.toDouble) / totalTime.toDouble / _processorCount).toLong else 0 + if (totalTime > 0) ((100d * value.toDouble) / totalTime.toDouble / _processorCount).toLong else 0 } _processCpuInstruments.user.record(toPercent(userTime)) @@ -156,7 +155,7 @@ class ProcessMetricsCollector(ec: ExecutionContext) extends ScheduledAction { } } - def terminate():Unit = + def terminate(): Unit = _doRun = false def updateInterval(duration: Duration): Unit = diff --git a/instrumentation/kamon-tapir/src/main/scala/kamon/instrumentation/tapir/TapirInstrumentation.scala b/instrumentation/kamon-tapir/src/main/scala/kamon/instrumentation/tapir/TapirInstrumentation.scala index 0208c5dcd..b7d19714f 100644 --- a/instrumentation/kamon-tapir/src/main/scala/kamon/instrumentation/tapir/TapirInstrumentation.scala +++ b/instrumentation/kamon-tapir/src/main/scala/kamon/instrumentation/tapir/TapirInstrumentation.scala @@ -33,7 +33,7 @@ class TapirInstrumentation extends InstrumentationBuilder { class TapirToRouteInterceptor -object TapirToRouteInterceptor { +object TapirToRouteInterceptor { def toRoute[I, E, O](@Argument(0) arg: Any, @SuperCall superCall: Callable[Route]): Route = { arg match { case endpoint: ServerEndpoint[_, _] => { @@ -45,7 +45,7 @@ object TapirToRouteInterceptor { val operationName = endpoint.info.name match { case Some(endpointName) if useEndpointNameAsOperationName => endpointName - case _ => endpoint.showPathTemplate() + case _ => endpoint.showPathTemplate() } Kamon.currentSpan() diff --git a/instrumentation/kamon-tapir/src/test/scala/kamon/instrumentation/tapir/TapirSpec.scala b/instrumentation/kamon-tapir/src/test/scala/kamon/instrumentation/tapir/TapirSpec.scala index e5f8641c1..9b5fbbebb 100644 --- a/instrumentation/kamon-tapir/src/test/scala/kamon/instrumentation/tapir/TapirSpec.scala +++ b/instrumentation/kamon-tapir/src/test/scala/kamon/instrumentation/tapir/TapirSpec.scala @@ -26,10 +26,10 @@ import sttp.client3.{HttpURLConnectionBackend, Identity, SttpBackend, UriContext import scala.concurrent.duration.DurationInt class TapirSpec extends AnyWordSpec with Matchers - with TestSpanReporter - with Eventually - with BeforeAndAfterAll - with OptionValues { + with TestSpanReporter + with Eventually + with BeforeAndAfterAll + with OptionValues { var backend: SttpBackend[Identity, Any] = _ @@ -43,7 +43,6 @@ class TapirSpec extends AnyWordSpec with Matchers backend.close() } - "the Tapir Akka HTTP instrumentation" should { "replace params in path when naming span" in { basicRequest diff --git a/instrumentation/kamon-tapir/src/test/scala/kamon/instrumentation/tapir/TestRoutes.scala b/instrumentation/kamon-tapir/src/test/scala/kamon/instrumentation/tapir/TestRoutes.scala index 9a4a8898f..2586c32ad 100644 --- a/instrumentation/kamon-tapir/src/test/scala/kamon/instrumentation/tapir/TestRoutes.scala +++ b/instrumentation/kamon-tapir/src/test/scala/kamon/instrumentation/tapir/TestRoutes.scala @@ -40,7 +40,7 @@ object TestRoutes { .in("mixed").in(path[Boolean]("other_param")) .in("types").out(plainBody[String]) private val nestedRoute = AkkaHttpServerInterpreter().toRoute( - nested.serverLogic[Future] { x => Future.successful(Right[Unit,String](x.toString())) } + nested.serverLogic[Future] { x => Future.successful(Right[Unit, String](x.toString())) } ) val routes = helloRoute ~ nestedRoute diff --git a/instrumentation/kamon-twitter-future/src/main/scala/kamon/instrumentation/futures/twitter/TwitterFutureInstrumentation.scala b/instrumentation/kamon-twitter-future/src/main/scala/kamon/instrumentation/futures/twitter/TwitterFutureInstrumentation.scala index 1d137bb9d..19081aa29 100644 --- a/instrumentation/kamon-twitter-future/src/main/scala/kamon/instrumentation/futures/twitter/TwitterFutureInstrumentation.scala +++ b/instrumentation/kamon-twitter-future/src/main/scala/kamon/instrumentation/futures/twitter/TwitterFutureInstrumentation.scala @@ -30,7 +30,6 @@ class TwitterFutureInstrumentation extends InstrumentationBuilder { .advise(isConstructor, CaptureCurrentContextOnExit) .advise(method("apply"), InvokeWithCapturedContext) - onType("com.twitter.util.Promise$Interruptible") .advise(isConstructor, classOf[InterruptiblePromiseConstructorAdvice]) } @@ -43,4 +42,4 @@ class InterruptibleHandlerWithContext(context: Context, delegate: PartialFunctio override def apply(v1: Throwable): Unit = Kamon.runWithContext(context)(delegate.apply(v1)) -} \ No newline at end of file +} diff --git a/instrumentation/kamon-twitter-future/src/test/scala/kamon/instrumentation/futures/twitter/FutureInstrumentationSpec.scala b/instrumentation/kamon-twitter-future/src/test/scala/kamon/instrumentation/futures/twitter/FutureInstrumentationSpec.scala index 08ea208e6..f7b531f23 100644 --- a/instrumentation/kamon-twitter-future/src/test/scala/kamon/instrumentation/futures/twitter/FutureInstrumentationSpec.scala +++ b/instrumentation/kamon-twitter-future/src/test/scala/kamon/instrumentation/futures/twitter/FutureInstrumentationSpec.scala @@ -27,7 +27,8 @@ import org.scalatest.wordspec.AnyWordSpec import java.util.concurrent.Executors -class FutureInstrumentationSpec extends AnyWordSpec with Matchers with ScalaFutures with PatienceConfiguration with OptionValues { +class FutureInstrumentationSpec extends AnyWordSpec with Matchers with ScalaFutures with PatienceConfiguration + with OptionValues { // NOTE: We have this test just to ensure that the Context propagation is working, but starting with Kamon 2.0 there // is no need to have explicit Runnable/Callable instrumentation because the instrumentation brought by the @@ -63,4 +64,3 @@ class FutureInstrumentationSpec extends AnyWordSpec with Matchers with ScalaFutu } } } - diff --git a/instrumentation/kamon-zio-2/src/main/scala/kamon/instrumentation/zio2/ZIO2Instrumentation.scala b/instrumentation/kamon-zio-2/src/main/scala/kamon/instrumentation/zio2/ZIO2Instrumentation.scala index 4e779edb4..f0fa0e41d 100644 --- a/instrumentation/kamon-zio-2/src/main/scala/kamon/instrumentation/zio2/ZIO2Instrumentation.scala +++ b/instrumentation/kamon-zio-2/src/main/scala/kamon/instrumentation/zio2/ZIO2Instrumentation.scala @@ -6,7 +6,6 @@ import kamon.instrumentation.context.HasContext import kanela.agent.api.instrumentation.InstrumentationBuilder import zio.{Exit, Fiber, Supervisor, UIO, Unsafe, ZEnvironment, ZIO} - /** * This works as follows. * - patches the defaultSupervisor val from Runtime to add our own supervisor. @@ -55,12 +54,16 @@ object HasStorage { } } - class NewSupervisor extends Supervisor[Any] { override def value(implicit trace: zio.Trace): UIO[Any] = ZIO.unit - override def onStart[R, E, A_](environment: ZEnvironment[R], effect: ZIO[R, E, A_], parent: Option[Fiber.Runtime[Any, Any]], fiber: Fiber.Runtime[E, A_])(implicit unsafe: Unsafe): Unit = { + override def onStart[R, E, A_]( + environment: ZEnvironment[R], + effect: ZIO[R, E, A_], + parent: Option[Fiber.Runtime[Any, Any]], + fiber: Fiber.Runtime[E, A_] + )(implicit unsafe: Unsafe): Unit = { fiber.asInstanceOf[HasContext].setContext(Kamon.currentContext()) } diff --git a/instrumentation/kamon-zio-2/src/test/scala/kamon/instrumentation/zio2/ZIO2InstrumentationSpec.scala b/instrumentation/kamon-zio-2/src/test/scala/kamon/instrumentation/zio2/ZIO2InstrumentationSpec.scala index 3d62b3ff1..6236e6f54 100644 --- a/instrumentation/kamon-zio-2/src/test/scala/kamon/instrumentation/zio2/ZIO2InstrumentationSpec.scala +++ b/instrumentation/kamon-zio-2/src/test/scala/kamon/instrumentation/zio2/ZIO2InstrumentationSpec.scala @@ -1,6 +1,5 @@ package kamon.instrumentation.zio2 - import kamon.Kamon import kamon.context.Context import kamon.tag.Lookups.plain @@ -18,7 +17,7 @@ import zio._ import scala.concurrent.duration.FiniteDuration class ZIO2InstrumentationSpec extends AnyWordSpec with Matchers with ScalaFutures with PatienceConfiguration - with OptionValues with Eventually with BeforeAndAfterEach { + with OptionValues with Eventually with BeforeAndAfterEach { protected implicit val zioRuntime: Runtime[Any] = Runtime.default @@ -65,7 +64,8 @@ class ZIO2InstrumentationSpec extends AnyWordSpec with Matchers with ScalaFuture } "must allow the context to be cleaned" in { - val anotherExecutor = Executor.fromExecutionContext(ExecutionContext.fromExecutorService(Executors.newFixedThreadPool(10))) + val anotherExecutor = + Executor.fromExecutionContext(ExecutionContext.fromExecutorService(Executors.newFixedThreadPool(10))) val context = Context.of("key", "value") val test = @@ -85,7 +85,8 @@ class ZIO2InstrumentationSpec extends AnyWordSpec with Matchers with ScalaFuture } "must be available across asynchronous boundaries" in { - val anotherExecutor: Executor = Executor.fromExecutionContext(ExecutionContext.fromExecutorService(Executors.newFixedThreadPool(1))) //pool 7 + val anotherExecutor: Executor = + Executor.fromExecutionContext(ExecutionContext.fromExecutorService(Executors.newFixedThreadPool(1))) // pool 7 val context = Context.of("key", "value") val test = for { @@ -93,14 +94,14 @@ class ZIO2InstrumentationSpec extends AnyWordSpec with Matchers with ScalaFuture len <- ZIO.succeed("Hello Kamon!").map(_.length) _ <- ZIO.succeed(len.toString) beforeChanging <- getKey - evalOnGlobalRes <-ZIO.sleep(Duration.Zero) *> getKey + evalOnGlobalRes <- ZIO.sleep(Duration.Zero) *> getKey outerSpanIdBeginning <- ZIO.succeed(Kamon.currentSpan().id.string) innerSpan <- ZIO.succeed(Kamon.clientSpanBuilder("Foo", "attempt").context(context).start()) innerSpanId1 <- ZIO.onExecutor(anotherExecutor)(ZIO.succeed(Kamon.currentSpan())) innerSpanId2 <- ZIO.succeed(Kamon.currentSpan()) _ <- ZIO.succeed(innerSpan.finish()) outerSpanIdEnd <- ZIO.succeed(Kamon.currentSpan().id.string) - evalOnAnotherEx <-ZIO.onExecutor(anotherExecutor)(ZIO.sleep(Duration.Zero).flatMap(_ => getKey)) + evalOnAnotherEx <- ZIO.onExecutor(anotherExecutor)(ZIO.sleep(Duration.Zero).flatMap(_ => getKey)) } yield { scope.close() withClue("before changing")(beforeChanging shouldBe "value") @@ -112,7 +113,7 @@ class ZIO2InstrumentationSpec extends AnyWordSpec with Matchers with ScalaFuture withClue("inner and outer should be different")(outerSpanIdBeginning should not equal innerSpan) } - unsafeRunZIO(test) + unsafeRunZIO(test) } @@ -124,6 +125,7 @@ class ZIO2InstrumentationSpec extends AnyWordSpec with Matchers with ScalaFuture ) val context = Context.of(Span.Key, parentSpan) implicit val ec = ExecutionContext.global + /** * test * - nestedLevel0 @@ -134,8 +136,10 @@ class ZIO2InstrumentationSpec extends AnyWordSpec with Matchers with ScalaFuture val test = for { span <- ZIO.succeed(Kamon.currentSpan()) nestedLevel0 <- meteredWithSpanCapture("level1-A")(ZIO.sleep(100.millis)) - nestedUpToLevel2 <- meteredWithSpanCapture("level1-B")(meteredWithSpanCapture("level2-B")(ZIO.sleep(100.millis))) - fiftyInParallel <- ZIO.foreachPar((0 to 49).toList)(i => meteredWithSpanCapture(s"operation$i")(ZIO.sleep(100.millis))) + nestedUpToLevel2 <- + meteredWithSpanCapture("level1-B")(meteredWithSpanCapture("level2-B")(ZIO.sleep(100.millis))) + fiftyInParallel <- + ZIO.foreachPar((0 to 49).toList)(i => meteredWithSpanCapture(s"operation$i")(ZIO.sleep(100.millis))) afterCede <- meteredWithSpanCapture("yieldNow")(ZIO.yieldNow.as(Kamon.currentSpan())) afterEverything <- ZIO.succeed(Kamon.currentSpan()) } yield { @@ -145,12 +149,10 @@ class ZIO2InstrumentationSpec extends AnyWordSpec with Matchers with ScalaFuture nestedUpToLevel2._1.id.string shouldBe nestedUpToLevel2._2._1.parentId.string fiftyInParallel.map(_._1.parentId.string).toSet shouldBe Set(span.id.string) fiftyInParallel.map(_._1.id.string).toSet should have size 50 - afterCede._1.id.string shouldBe afterCede._2.id.string //A cede should not cause the span to be lost + afterCede._1.id.string shouldBe afterCede._2.id.string // A cede should not cause the span to be lost afterEverything.id.string shouldBe span.id.string } - - val result = scala.concurrent.Future.sequence( (1 to 100).toList.map { _ => Unsafe.unsafe { implicit unsafe => @@ -172,19 +174,19 @@ class ZIO2InstrumentationSpec extends AnyWordSpec with Matchers with ScalaFuture private def meteredWithSpanCapture[A](operation: String)(io: UIO[A]): UIO[(Span, A)] = { ZIO.scoped { ZIO.acquireRelease { + for { + initialCtx <- ZIO.succeed(Kamon.currentContext()) + parentSpan <- ZIO.succeed(Kamon.currentSpan()) + newSpan <- ZIO.succeed(Kamon.spanBuilder(operation).context(initialCtx).asChildOf(parentSpan).start()) + _ <- ZIO.succeed(Kamon.storeContext(initialCtx.withEntry(Span.Key, newSpan))) + } yield (initialCtx, newSpan) + } { + case (initialCtx, span) => for { - initialCtx <- ZIO.succeed(Kamon.currentContext()) - parentSpan <- ZIO.succeed(Kamon.currentSpan()) - newSpan <- ZIO.succeed(Kamon.spanBuilder(operation).context(initialCtx).asChildOf(parentSpan).start()) - _ <- ZIO.succeed(Kamon.storeContext(initialCtx.withEntry(Span.Key, newSpan))) - } yield (initialCtx, newSpan) - }{ - case (initialCtx, span) => - for { - _ <- ZIO.succeed(span.finish()) - _ <- ZIO.succeed(Kamon.storeContext(initialCtx)) - } yield () - } *> ZIO.succeed(Kamon.currentSpan()).zipPar(io) - } + _ <- ZIO.succeed(span.finish()) + _ <- ZIO.succeed(Kamon.storeContext(initialCtx)) + } yield () + } *> ZIO.succeed(Kamon.currentSpan()).zipPar(io) + } } } diff --git a/reporters/kamon-apm-reporter/src/main/scala/kamon/apm/ApiClient.scala b/reporters/kamon-apm-reporter/src/main/scala/kamon/apm/ApiClient.scala index afd1c9455..965fc7cf5 100644 --- a/reporters/kamon-apm-reporter/src/main/scala/kamon/apm/ApiClient.scala +++ b/reporters/kamon-apm-reporter/src/main/scala/kamon/apm/ApiClient.scala @@ -54,7 +54,7 @@ class ApiClient(settings: Settings) { val clock = Kamon.clock() val timeSinceLastPost = Duration.between(_lastAttempt, clock.instant()) - if(timeSinceLastPost.compareTo(settings.clientBackoff) < 0) backoff + if (timeSinceLastPost.compareTo(settings.clientBackoff) < 0) backoff val request: () => Response = () => { val reqBody = RequestBody.create(MediaType.parse("application/octet-stream"), body) @@ -83,25 +83,33 @@ class ApiClient(settings: Settings) { case 401 => _logger.trace("Request to the Kamon APM [{}] endpoint failed due to Invalid API Key", endpointName) case status if retries > 0 => - _logger.warn(s"Failed to process request to the Kamon APM [${endpointName}] endpoint with status code [${status}]. " + - s"Retrying shortly ($retries left)...") + _logger.warn( + s"Failed to process request to the Kamon APM [${endpointName}] endpoint with status code [${status}]. " + + s"Retrying shortly ($retries left)..." + ) backoff postWithRetry(body, endpointName, apiUrl, retries - 1) case status => - _logger.warn(s"Failed to process request to the Kamon APM [${endpointName}] endpoint with status code [${status}] " + - "and no retries left. Dropping the request.") + _logger.warn( + s"Failed to process request to the Kamon APM [${endpointName}] endpoint with status code [${status}] " + + "and no retries left. Dropping the request." + ) } case Failure(connectionException) if retries > 0 => - _logger.warn(s"Failed to reach the Kamon APM [${endpointName}] endpoint. Retrying shortly ($retries left)...", - connectionException) + _logger.warn( + s"Failed to reach the Kamon APM [${endpointName}] endpoint. Retrying shortly ($retries left)...", + connectionException + ) backoff postWithRetry(body, endpointName, apiUrl, retries - 1) case Failure(connectionException) => - _logger.error(s"Failed to reach the Kamon APM [${endpointName}] endpoint with no retries left. Dropping the request.", - connectionException) + _logger.error( + s"Failed to reach the Kamon APM [${endpointName}] endpoint with no retries left. Dropping the request.", + connectionException + ) } } diff --git a/reporters/kamon-apm-reporter/src/main/scala/kamon/apm/KamonApm.scala b/reporters/kamon-apm-reporter/src/main/scala/kamon/apm/KamonApm.scala index a04d73158..16c008b15 100644 --- a/reporters/kamon-apm-reporter/src/main/scala/kamon/apm/KamonApm.scala +++ b/reporters/kamon-apm-reporter/src/main/scala/kamon/apm/KamonApm.scala @@ -33,7 +33,6 @@ import java.util.concurrent.TimeUnit import scala.concurrent.{ExecutionContext, Future} import scala.collection.JavaConverters.seqAsJavaListConverter - class KamonApm(configPath: String, executionContext: ExecutionContext) extends CombinedReporter { private val _maxSnapshotAge = Duration.ofMinutes(30) private var _settings = readSettings(Kamon.config(), configPath) @@ -41,9 +40,11 @@ class KamonApm(configPath: String, executionContext: ExecutionContext) extends C private val _unitConverter = new UnitConverter(time.nanoseconds, information.bytes, DynamicRange.Default) private var _resource = buildResource() - if(isAcceptableApiKey(_settings.apiKey)) { + if (isAcceptableApiKey(_settings.apiKey)) { val serviceName = Kamon.environment.service - _logger.info(s"Starting the Kamon APM Reporter. Your service will be displayed as [${serviceName}] at https://apm.kamon.io/") + _logger.info( + s"Starting the Kamon APM Reporter. Your service will be displayed as [${serviceName}] at https://apm.kamon.io/" + ) Future { reportBoot() }(executionContext).failed.foreach(t => _logger.error("Failed to say Hello to Kamon APM", t))(executionContext) @@ -86,22 +87,26 @@ class KamonApm(configPath: String, executionContext: ExecutionContext) extends C override def reportPeriodSnapshot(snapshot: PeriodSnapshot): Unit = { val snapshotAge = java.time.Duration.between(snapshot.to, Kamon.clock().instant()).toMillis - if(snapshotAge >= 0 && snapshotAge < _maxSnapshotAge.toMillis) - if(isAcceptableApiKey(_settings.apiKey)) + if (snapshotAge >= 0 && snapshotAge < _maxSnapshotAge.toMillis) + if (isAcceptableApiKey(_settings.apiKey)) reportMetricsBatch(snapshot) else _logger.error(s"Dropping metrics because an invalid API key has been configured [${_settings.apiKey}]") else - _logger.warn("Dropping stale metrics for period from: [{}], to: [{}]. The snapshot is [{} millis] old", - snapshot.from.toEpochMilli().toString(), snapshot.to.toEpochMilli().toString(), snapshotAge.toString()) + _logger.warn( + "Dropping stale metrics for period from: [{}], to: [{}]. The snapshot is [{} millis] old", + snapshot.from.toEpochMilli().toString(), + snapshot.to.toEpochMilli().toString(), + snapshotAge.toString() + ) } - override def reportSpans(spans: Seq[Span.Finished]): Unit = if(spans.nonEmpty) { - if(isAcceptableApiKey(_settings.apiKey)) { + override def reportSpans(spans: Seq[Span.Finished]): Unit = if (spans.nonEmpty) { + if (isAcceptableApiKey(_settings.apiKey)) { val spansFinishLimit = Kamon.clock().instant().minus(_maxSnapshotAge) val recentSpans = spans.filter(_.to.isAfter(spansFinishLimit)) - if(recentSpans.nonEmpty) { + if (recentSpans.nonEmpty) { val batch = ingestion.v2.IngestionV2.SpansBatch.newBuilder() .setApiKey(_settings.apiKey) .setResource(_resource) @@ -124,7 +129,7 @@ class KamonApm(configPath: String, executionContext: ExecutionContext) extends C val gauges = snapshot.gauges.map(g => toApmGauge(g, fromEpoch, endEpoch)) val counters = snapshot.counters.map(c => toApmCounter(c, fromEpoch, endEpoch)) val allMetrics = histograms ++ timers ++ rangeSamplers ++ gauges ++ counters - val metricsBatch = ingestion.v2.IngestionV2.MetricsBatch.newBuilder() + val metricsBatch = ingestion.v2.IngestionV2.MetricsBatch.newBuilder() .setApiKey(_settings.apiKey) .setResource(_resource) .addAllMetrics(allMetrics.asJava) @@ -152,8 +157,11 @@ class KamonApm(configPath: String, executionContext: ExecutionContext) extends C _httpClient.foreach(_.postGoodbye(goodBye)) } - - private def toApmCounter(metric: MetricSnapshot.Values[Long], fromEpoch: Long, toEpoch: Long): ingestion.v2.IngestionV2.Metric = { + private def toApmCounter( + metric: MetricSnapshot.Values[Long], + fromEpoch: Long, + toEpoch: Long + ): ingestion.v2.IngestionV2.Metric = { val dataPoints = metric.instruments.map { case Instrument.Snapshot(tags, count) => ingestion.v2.IngestionV2.Metric.DataPoint.newBuilder() @@ -172,7 +180,11 @@ class KamonApm(configPath: String, executionContext: ExecutionContext) extends C .build() } - private def toApmGauge(metric: MetricSnapshot.Values[Double], fromEpoch: Long, toEpoch: Long): ingestion.v2.IngestionV2.Metric = { + private def toApmGauge( + metric: MetricSnapshot.Values[Double], + fromEpoch: Long, + toEpoch: Long + ): ingestion.v2.IngestionV2.Metric = { val dataPoints = metric.instruments.map { case Instrument.Snapshot(tags, value) => ingestion.v2.IngestionV2.Metric.DataPoint.newBuilder() @@ -191,7 +203,11 @@ class KamonApm(configPath: String, executionContext: ExecutionContext) extends C .build() } - private def toApmHistogram(metric: MetricSnapshot.Distributions, fromEpoch: Long, toEpoch: Long): ingestion.v2.IngestionV2.Metric = { + private def toApmHistogram( + metric: MetricSnapshot.Distributions, + fromEpoch: Long, + toEpoch: Long + ): ingestion.v2.IngestionV2.Metric = { val dataPoints = metric.instruments.map { case Instrument.Snapshot(tags, distribution) => val convertedDistribution = _unitConverter.convertDistribution(distribution, metric.settings.unit) @@ -216,9 +232,9 @@ class KamonApm(configPath: String, executionContext: ExecutionContext) extends C } val metricUnit = metric.settings.unit.dimension match { - case Dimension.Time => time.nanoseconds.magnitude.name - case Dimension.Information => information.bytes.magnitude.name - case _ => metric.settings.unit.magnitude.name + case Dimension.Time => time.nanoseconds.magnitude.name + case Dimension.Information => information.bytes.magnitude.name + case _ => metric.settings.unit.magnitude.name } ingestion.v2.IngestionV2.Metric.newBuilder() @@ -234,7 +250,7 @@ class KamonApm(configPath: String, executionContext: ExecutionContext) extends C } private def toApmTags(tagSet: TagSet): java.lang.Iterable[ingestion.v2.IngestionV2.Tag] = { - import ingestion.v2.IngestionV2.{ Tag => ApmTag } + import ingestion.v2.IngestionV2.{Tag => ApmTag} val tags = new util.LinkedList[ApmTag]() tagSet.iterator().foreach { @@ -293,7 +309,7 @@ class KamonApm(configPath: String, executionContext: ExecutionContext) extends C } private def convertSpanStatus(span: Span.Finished): ingestion.v2.IngestionV2.Span.Status = { - if(span.hasError) + if (span.hasError) ingestion.v2.IngestionV2.Span.Status.Error else ingestion.v2.IngestionV2.Span.Status.Ok @@ -301,7 +317,6 @@ class KamonApm(configPath: String, executionContext: ExecutionContext) extends C } - object KamonApm { class Factory extends ModuleFactory { @@ -309,4 +324,3 @@ object KamonApm { new KamonApm(settings.executionContext) } } - diff --git a/reporters/kamon-apm-reporter/src/main/scala/kamon/apm/package.scala b/reporters/kamon-apm-reporter/src/main/scala/kamon/apm/package.scala index 26e6e914c..595b4489d 100644 --- a/reporters/kamon-apm-reporter/src/main/scala/kamon/apm/package.scala +++ b/reporters/kamon-apm-reporter/src/main/scala/kamon/apm/package.scala @@ -31,22 +31,22 @@ package object apm { val apmConfig = config.getConfig(path) val apiKey = apmConfig.getString("api-key") - if(apiKey.equals("none")) + if (apiKey.equals("none")) _logger.error("No API key defined in the kamon.apm.api-key setting") - Settings ( - apiKey = apiKey, + Settings( + apiKey = apiKey, connectionTimeout = apmConfig.getDuration("client.timeouts.connection"), - readTimeout = apmConfig.getDuration("client.timeouts.read"), - baseUrl = apmConfig.getString("base-url"), - bootRetries = apmConfig.getInt("retries.boot"), - ingestionRetries = apmConfig.getInt("retries.ingestion"), - shutdownRetries = apmConfig.getInt("retries.shutdown"), - tracingRetries = apmConfig.getInt("retries.tracing"), - clientBackoff = apmConfig.getDuration("client.backoff"), - proxyHost = apmConfig.getString("proxy.host"), - proxyPort = apmConfig.getInt("proxy.port"), - proxy = apmConfig.getString("proxy.type").toLowerCase match { + readTimeout = apmConfig.getDuration("client.timeouts.read"), + baseUrl = apmConfig.getString("base-url"), + bootRetries = apmConfig.getInt("retries.boot"), + ingestionRetries = apmConfig.getInt("retries.ingestion"), + shutdownRetries = apmConfig.getInt("retries.shutdown"), + tracingRetries = apmConfig.getInt("retries.tracing"), + clientBackoff = apmConfig.getDuration("client.backoff"), + proxyHost = apmConfig.getString("proxy.host"), + proxyPort = apmConfig.getInt("proxy.port"), + proxy = apmConfig.getString("proxy.type").toLowerCase match { case "system" => None case "socks" => Some(Proxy.Type.SOCKS) case "https" => Some(Proxy.Type.HTTP) @@ -57,7 +57,7 @@ package object apm { def isAcceptableApiKey(apiKey: String): Boolean = apiKey != null && apiKey.length == 26 && _apiKeyPattern.matcher(apiKey).matches() - case class Settings ( + case class Settings( apiKey: String, connectionTimeout: Duration, readTimeout: Duration, @@ -71,10 +71,10 @@ package object apm { proxyHost: String, proxyPort: Int ) { - def metricsRoute = s"$baseUrl/metrics" - def helloRoute = s"$baseUrl/hello" - def goodbyeRoute = s"$baseUrl/goodbye" - def spansRoute = s"$baseUrl/spans" + def metricsRoute = s"$baseUrl/metrics" + def helloRoute = s"$baseUrl/hello" + def goodbyeRoute = s"$baseUrl/goodbye" + def spansRoute = s"$baseUrl/spans" } /* @@ -85,11 +85,11 @@ package object apm { def countsArrayIndex(value: Long): Int = { val SubBucketHalfCountMagnitude = 7 - val SubBucketHalfCount = 128 - val UnitMagnitude = 0 - val SubBucketCount = Math.pow(2, SubBucketHalfCountMagnitude + 1).toInt - val LeadingZeroCountBase = 64 - UnitMagnitude - SubBucketHalfCountMagnitude - 1 - val SubBucketMask = (SubBucketCount.toLong - 1) << UnitMagnitude + val SubBucketHalfCount = 128 + val UnitMagnitude = 0 + val SubBucketCount = Math.pow(2, SubBucketHalfCountMagnitude + 1).toInt + val LeadingZeroCountBase = 64 - UnitMagnitude - SubBucketHalfCountMagnitude - 1 + val SubBucketMask = (SubBucketCount.toLong - 1) << UnitMagnitude def countsArrayIndex(bucketIndex: Int, subBucketIndex: Int): Int = { val bucketBaseIndex = (bucketIndex + 1) << SubBucketHalfCountMagnitude @@ -100,7 +100,7 @@ package object apm { def getBucketIndex(value: Long): Int = LeadingZeroCountBase - java.lang.Long.numberOfLeadingZeros(value | SubBucketMask) - def getSubBucketIndex(value: Long, bucketIndex: Long): Int = + def getSubBucketIndex(value: Long, bucketIndex: Long): Int = Math.floor(value / Math.pow(2, (bucketIndex + UnitMagnitude))).toInt if (value < 0) throw new ArrayIndexOutOfBoundsException("Histogram recorded value cannot be negative.") @@ -109,5 +109,4 @@ package object apm { countsArrayIndex(bucketIndex, subBucketIndex) } - } diff --git a/reporters/kamon-apm-reporter/src/test/scala/kamon/apm/ReporterSpec.scala b/reporters/kamon-apm-reporter/src/test/scala/kamon/apm/ReporterSpec.scala index 0aa89bce0..c24907534 100644 --- a/reporters/kamon-apm-reporter/src/test/scala/kamon/apm/ReporterSpec.scala +++ b/reporters/kamon-apm-reporter/src/test/scala/kamon/apm/ReporterSpec.scala @@ -24,41 +24,40 @@ import java.time.Instant import scala.concurrent.duration._ import scala.concurrent.{ExecutionContext, Future} - class ReporterSpec extends TestKit(ActorSystem("MetricReporterSpec")) - with AnyWordSpecLike with Matchers with BeforeAndAfterAll with ImplicitSender with BeforeAndAfterEach with Eventually { + with AnyWordSpecLike with Matchers with BeforeAndAfterAll with ImplicitSender with BeforeAndAfterEach + with Eventually { var server: Future[ServerBinding] = null - private var (helloCount, goodByeCount, ingestCount, tracingCount) = (0,0,0,0) + private var (helloCount, goodByeCount, ingestCount, tracingCount) = (0, 0, 0, 0) override def beforeAll(): Unit = { implicit val materializer: ActorMaterializer = ActorMaterializer() implicit val executionContext: ExecutionContext = system.dispatcher - lazy val routes: Route = entity(as[Array[Byte]]) { buff => post { pathPrefix("v2") { path("hello") { - helloCount+=1 + helloCount += 1 testActor ! "hello" - if(helloCount > 2) complete("hello") else complete(StatusCodes.InternalServerError) + if (helloCount > 2) complete("hello") else complete(StatusCodes.InternalServerError) } ~ path("goodbye") { - goodByeCount+=1 + goodByeCount += 1 testActor ! "goodbye" - if(goodByeCount > 2) complete("good") else complete(StatusCodes.InternalServerError) + if (goodByeCount > 2) complete("good") else complete(StatusCodes.InternalServerError) } ~ path("metrics") { - ingestCount+=1 + ingestCount += 1 testActor ! "metrics" - if(ingestCount > 2) complete("") else complete(StatusCodes.InternalServerError) + if (ingestCount > 2) complete("") else complete(StatusCodes.InternalServerError) } ~ - path("spans") { - tracingCount+=1 + path("spans") { + tracingCount += 1 testActor ! "spans" - if(tracingCount > 2) complete("") else complete(StatusCodes.InternalServerError) + if (tracingCount > 2) complete("") else complete(StatusCodes.InternalServerError) } } } @@ -112,9 +111,22 @@ class ReporterSpec extends TestKit(ActorSystem("MetricReporterSpec")) } "retry span ingestion" in { - val span = Span.Finished(Identifier.Empty, Trace.Empty, Identifier.Empty, "", false, false, - Instant.now(), Instant.now(), Span.Kind.Unknown, Span.Position.Unknown, - TagSet.Empty, TagSet.Empty, Seq.empty, Seq.empty) + val span = Span.Finished( + Identifier.Empty, + Trace.Empty, + Identifier.Empty, + "", + false, + false, + Instant.now(), + Instant.now(), + Span.Kind.Unknown, + Span.Position.Unknown, + TagSet.Empty, + TagSet.Empty, + Seq.empty, + Seq.empty + ) reporter.reportSpans(Seq(span)) expectMsg("spans") diff --git a/reporters/kamon-datadog/src/main/scala/kamon/datadog/DatadogAPIReporter.scala b/reporters/kamon-datadog/src/main/scala/kamon/datadog/DatadogAPIReporter.scala index 00ed29ea5..4c07b0899 100644 --- a/reporters/kamon-datadog/src/main/scala/kamon/datadog/DatadogAPIReporter.scala +++ b/reporters/kamon-datadog/src/main/scala/kamon/datadog/DatadogAPIReporter.scala @@ -18,21 +18,21 @@ package kamon.datadog import java.lang.StringBuilder import java.nio.charset.StandardCharsets -import java.text.{ DecimalFormat, DecimalFormatSymbols } +import java.text.{DecimalFormat, DecimalFormatSymbols} import java.time.Duration import java.util.Locale import com.typesafe.config.Config -import kamon.metric.MeasurementUnit.Dimension.{ Information, Time } -import kamon.metric.{ MeasurementUnit, MetricSnapshot, PeriodSnapshot } -import kamon.tag.{ Tag, TagSet } -import kamon.util.{ EnvironmentTags, Filter } -import kamon.{ module, Kamon } +import kamon.metric.MeasurementUnit.Dimension.{Information, Time} +import kamon.metric.{MeasurementUnit, MetricSnapshot, PeriodSnapshot} +import kamon.tag.{Tag, TagSet} +import kamon.util.{EnvironmentTags, Filter} +import kamon.{module, Kamon} import kamon.datadog.DatadogAPIReporter.Configuration -import kamon.module.{ MetricReporter, ModuleFactory } +import kamon.module.{MetricReporter, ModuleFactory} import org.slf4j.LoggerFactory -import scala.util.{ Failure, Success } +import scala.util.{Failure, Success} class DatadogAPIReporterFactory extends ModuleFactory { override def create(settings: ModuleFactory.Settings): DatadogAPIReporter = { @@ -41,7 +41,10 @@ class DatadogAPIReporterFactory extends ModuleFactory { } } -class DatadogAPIReporter(@volatile private var configuration: Configuration, @volatile private var httpClient: HttpClient) extends MetricReporter { +class DatadogAPIReporter( + @volatile private var configuration: Configuration, + @volatile private var httpClient: HttpClient +) extends MetricReporter { import DatadogAPIReporter._ private val logger = LoggerFactory.getLogger(classOf[DatadogAPIReporter]) @@ -75,7 +78,7 @@ class DatadogAPIReporter(@volatile private var configuration: Configuration, @vo val timestamp = snapshot.from.getEpochSecond.toString val host = Kamon.environment.host - val interval = Math.round(Duration.between(snapshot.from, snapshot.to).toMillis() / 1000D) + val interval = Math.round(Duration.between(snapshot.from, snapshot.to).toMillis() / 1000d) val seriesBuilder = new StringBuilder() def addDistribution(metric: MetricSnapshot.Distributions): Unit = { @@ -86,21 +89,30 @@ class DatadogAPIReporter(@volatile private var configuration: Configuration, @vo val average = if (dist.count > 0L) (dist.sum / dist.count) else 0L addMetric(metric.name + ".avg", valueFormat.format(scale(average, unit)), gauge, d.tags) addMetric(metric.name + ".count", valueFormat.format(dist.count), count, d.tags) - addMetric(metric.name + ".median", valueFormat.format(scale(dist.percentile(50D).value, unit)), gauge, d.tags) - addMetric(metric.name + ".95percentile", valueFormat.format(scale(dist.percentile(95D).value, unit)), gauge, d.tags) + addMetric(metric.name + ".median", valueFormat.format(scale(dist.percentile(50d).value, unit)), gauge, d.tags) + addMetric( + metric.name + ".95percentile", + valueFormat.format(scale(dist.percentile(95d).value, unit)), + gauge, + d.tags + ) addMetric(metric.name + ".max", valueFormat.format(scale(dist.max, unit)), gauge, d.tags) addMetric(metric.name + ".min", valueFormat.format(scale(dist.min, unit)), gauge, d.tags) } } def addMetric(metricName: String, value: String, metricType: String, tags: TagSet): Unit = { - val customTags = (configuration.extraTags ++ tags.iterator(_.toString).map(p => p.key -> p.value).filter(t => configuration.tagFilter.accept(t._1))).map { case (k, v) ⇒ quote"$k:$v" } + val customTags = (configuration.extraTags ++ tags.iterator(_.toString).map(p => p.key -> p.value).filter(t => + configuration.tagFilter.accept(t._1) + )).map { case (k, v) ⇒ quote"$k:$v" } val allTagsString = customTags.mkString("[", ",", "]") if (seriesBuilder.length() > 0) seriesBuilder.append(",") seriesBuilder - .append(s"""{"metric":"$metricName","interval":$interval,"points":[[$timestamp,$value]],"type":"$metricType","host":"$host","tags":$allTagsString}""") + .append( + s"""{"metric":"$metricName","interval":$interval,"points":[[$timestamp,$value]],"type":"$metricType","host":"$host","tags":$allTagsString}""" + ) } snapshot.counters.foreach { snap => @@ -149,7 +161,13 @@ private object DatadogAPIReporter { val count = "count" val gauge = "gauge" - case class Configuration(httpConfig: Config, timeUnit: MeasurementUnit, informationUnit: MeasurementUnit, extraTags: Seq[(String, String)], tagFilter: Filter) + case class Configuration( + httpConfig: Config, + timeUnit: MeasurementUnit, + informationUnit: MeasurementUnit, + extraTags: Seq[(String, String)], + tagFilter: Filter + ) implicit class QuoteInterp(val sc: StringContext) extends AnyVal { def quote(args: Any*): String = "\"" + sc.s(args: _*) + "\"" @@ -162,7 +180,9 @@ private object DatadogAPIReporter { timeUnit = readTimeUnit(datadogConfig.getString("time-unit")), informationUnit = readInformationUnit(datadogConfig.getString("information-unit")), // Remove the "host" tag since it gets added to the datadog payload separately - EnvironmentTags.from(Kamon.environment, datadogConfig.getConfig("environment-tags")).without("host").all().map(p => p.key -> Tag.unwrapValue(p).toString), + EnvironmentTags.from(Kamon.environment, datadogConfig.getConfig("environment-tags")).without("host").all().map( + p => p.key -> Tag.unwrapValue(p).toString + ), Kamon.filter("kamon.datadog.environment-tags.filter") ) } diff --git a/reporters/kamon-datadog/src/main/scala/kamon/datadog/DatadogAgentReporter.scala b/reporters/kamon-datadog/src/main/scala/kamon/datadog/DatadogAgentReporter.scala index d4df486a5..b6a804ec3 100644 --- a/reporters/kamon-datadog/src/main/scala/kamon/datadog/DatadogAgentReporter.scala +++ b/reporters/kamon-datadog/src/main/scala/kamon/datadog/DatadogAgentReporter.scala @@ -19,15 +19,15 @@ package kamon.datadog import java.net.InetSocketAddress import java.nio.ByteBuffer import java.nio.channels.DatagramChannel -import java.text.{ DecimalFormat, DecimalFormatSymbols } +import java.text.{DecimalFormat, DecimalFormatSymbols} import java.util.Locale import com.typesafe.config.Config -import kamon.{ module, ClassLoading, Kamon } -import kamon.metric.{ MeasurementUnit, PeriodSnapshot } -import kamon.metric.MeasurementUnit.{ information, Dimension } -import kamon.metric.MeasurementUnit.Dimension.{ Information, Time } -import kamon.module.{ MetricReporter, ModuleFactory } +import kamon.{module, ClassLoading, Kamon} +import kamon.metric.{MeasurementUnit, PeriodSnapshot} +import kamon.metric.MeasurementUnit.{information, Dimension} +import kamon.metric.MeasurementUnit.Dimension.{Information, Time} +import kamon.module.{MetricReporter, ModuleFactory} import kamon.tag.TagSet import kamon.util.EnvironmentTags import org.slf4j.LoggerFactory @@ -38,14 +38,16 @@ class DatadogAgentReporterFactory extends ModuleFactory { } } // 1 arg constructor is intended for injecting config via unit tests -class DatadogAgentReporter private[datadog] (@volatile private var config: DatadogAgentReporter.Configuration) extends MetricReporter { +class DatadogAgentReporter private[datadog] (@volatile private var config: DatadogAgentReporter.Configuration) + extends MetricReporter { import DatadogAgentReporter._ private val symbols = DecimalFormatSymbols.getInstance(Locale.US) symbols.setDecimalSeparator('.') // Just in case there is some weird locale config we are not aware of. // Absurdly high number of decimal digits, let the other end lose precision if it needs to. - private val samplingRateFormat = new DecimalFormat("#.################################################################", symbols) + private val samplingRateFormat = + new DecimalFormat("#.################################################################", symbols) private val valueFormat = new DecimalFormat("#0.#########", symbols) logger.info("Started the Kamon Datadog reporter") @@ -62,14 +64,26 @@ class DatadogAgentReporter private[datadog] (@volatile private var config: Datad counter <- snapshot.counters instrument <- counter.instruments } { - config.packetBuffer.appendMeasurement(counter.name, config.measurementFormatter.formatMeasurement(encodeDatadogCounter(instrument.value, counter.settings.unit), instrument.tags)) + config.packetBuffer.appendMeasurement( + counter.name, + config.measurementFormatter.formatMeasurement( + encodeDatadogCounter(instrument.value, counter.settings.unit), + instrument.tags + ) + ) } for { gauge <- snapshot.gauges instrument <- gauge.instruments } { - config.packetBuffer.appendMeasurement(gauge.name, config.measurementFormatter.formatMeasurement(encodeDatadogGauge(instrument.value, gauge.settings.unit), instrument.tags)) + config.packetBuffer.appendMeasurement( + gauge.name, + config.measurementFormatter.formatMeasurement( + encodeDatadogGauge(instrument.value, gauge.settings.unit), + instrument.tags + ) + ) } for { @@ -78,7 +92,10 @@ class DatadogAgentReporter private[datadog] (@volatile private var config: Datad bucket <- instruments.value.bucketsIterator } { - val bucketData = config.measurementFormatter.formatMeasurement(encodeDatadogHistogramBucket(bucket.value, bucket.frequency, metric.settings.unit), instruments.tags) + val bucketData = config.measurementFormatter.formatMeasurement( + encodeDatadogHistogramBucket(bucket.value, bucket.frequency, metric.settings.unit), + instruments.tags + ) config.packetBuffer.appendMeasurement(metric.name, bucketData) } @@ -88,8 +105,10 @@ class DatadogAgentReporter private[datadog] (@volatile private var config: Datad private def encodeDatadogHistogramBucket(value: Long, frequency: Long, unit: MeasurementUnit): String = { val metricType = if (unit.dimension == Dimension.Time) "ms" else "h" - val samplingRate: Double = 1D / frequency.toDouble - valueFormat.format(scale(value, unit)) + "|" + metricType + (if (samplingRate != 1D) "|@" + samplingRateFormat.format(samplingRate) else "") + val samplingRate: Double = 1d / frequency.toDouble + valueFormat.format(scale(value, unit)) + "|" + metricType + (if (samplingRate != 1d) + "|@" + samplingRateFormat.format(samplingRate) + else "") } private def encodeDatadogCounter(count: Long, unit: MeasurementUnit): String = @@ -99,9 +118,10 @@ class DatadogAgentReporter private[datadog] (@volatile private var config: Datad valueFormat.format(scale(value, unit)) + "|g" private def scale(value: Double, unit: MeasurementUnit): Double = unit.dimension match { - case Time if unit.magnitude != config.timeUnit.magnitude => MeasurementUnit.convert(value, unit, config.timeUnit) - case Information if unit.magnitude != information.bytes.magnitude => MeasurementUnit.convert(value, unit, information.bytes) - case _ => value.toDouble + case Time if unit.magnitude != config.timeUnit.magnitude => MeasurementUnit.convert(value, unit, config.timeUnit) + case Information if unit.magnitude != information.bytes.magnitude => + MeasurementUnit.convert(value, unit, information.bytes) + case _ => value.toDouble } } @@ -122,7 +142,7 @@ object DatadogAgentReporter { override def formatMeasurement( measurementData: String, - tags: TagSet + tags: TagSet ): String = { val filteredTags = envTags.iterator(_.toString) ++ tags.iterator(_.toString).filter(p => filter.accept(p.key)) @@ -166,10 +186,10 @@ object DatadogAgentReporter { } private[datadog] case class Configuration( - timeUnit: MeasurementUnit, - informationUnit: MeasurementUnit, + timeUnit: MeasurementUnit, + informationUnit: MeasurementUnit, measurementFormatter: MeasurementFormatter, - packetBuffer: PacketBuffer + packetBuffer: PacketBuffer ) trait PacketBuffer { diff --git a/reporters/kamon-datadog/src/main/scala/kamon/datadog/DatadogSpanReporter.scala b/reporters/kamon-datadog/src/main/scala/kamon/datadog/DatadogSpanReporter.scala index de07f31e9..63578be3f 100644 --- a/reporters/kamon-datadog/src/main/scala/kamon/datadog/DatadogSpanReporter.scala +++ b/reporters/kamon-datadog/src/main/scala/kamon/datadog/DatadogSpanReporter.scala @@ -21,15 +21,15 @@ import java.time.Duration import com.grack.nanojson.{JsonArray, JsonObject, JsonWriter} import com.typesafe.config.Config import kamon.trace.Span -import kamon.{ ClassLoading, Kamon } +import kamon.{ClassLoading, Kamon} import kamon.datadog.DatadogSpanReporter.Configuration -import kamon.module.{ ModuleFactory, SpanReporter } -import kamon.tag.{ Lookups, Tag, TagSet } +import kamon.module.{ModuleFactory, SpanReporter} +import kamon.tag.{Lookups, Tag, TagSet} import kamon.trace.Span.TagKeys -import kamon.util.{ EnvironmentTags, Filter } +import kamon.util.{EnvironmentTags, Filter} import org.slf4j.LoggerFactory -import scala.util.{ Failure } +import scala.util.{Failure} trait KamonDataDogTranslator { def translate(span: Span.Finished, additionalTags: TagSet, tagFilter: Filter): DdSpan @@ -74,8 +74,8 @@ object DatadogSpanReporter { case class Configuration( translator: KamonDataDogTranslator, httpClient: HttpClient, - tagFilter: Filter, - envTags: TagSet + tagFilter: Filter, + envTags: TagSet ) private[kamon] val httpConfigPath = "kamon.datadog.trace" diff --git a/reporters/kamon-datadog/src/main/scala/kamon/datadog/DdSpan.scala b/reporters/kamon-datadog/src/main/scala/kamon/datadog/DdSpan.scala index 354029c76..01ad0e6fa 100644 --- a/reporters/kamon-datadog/src/main/scala/kamon/datadog/DdSpan.scala +++ b/reporters/kamon-datadog/src/main/scala/kamon/datadog/DdSpan.scala @@ -21,17 +21,18 @@ import java.time.Duration import com.grack.nanojson.JsonObject case class DdSpan( - traceId: BigInt, - spanId: BigInt, + traceId: BigInt, + spanId: BigInt, parentId: Option[BigInt], - name: String, + name: String, resource: String, - service: String, + service: String, spanType: String, - start: Long, + start: Long, duration: Duration, - meta: Map[String, String], - error: Boolean) { + meta: Map[String, String], + error: Boolean +) { def toJson(): JsonObject = { val metaBuilder = JsonObject.builder @@ -52,10 +53,10 @@ case class DdSpan( .`object`("meta", metaObj) .value("error", if (error) 1 else 0) .`object`("metrics") - // This tells the datadog agent to keep the trace. We've already determined sampling here or we wouldn't - // be in this method. Keep in mind this DOES NOT respect sampling rates in the datadog agent - // https://docs.datadoghq.com/tracing/guide/trace_sampling_and_storage/#client-implementation - .value("_sampling_priority_v1", 1) + // This tells the datadog agent to keep the trace. We've already determined sampling here or we wouldn't + // be in this method. Keep in mind this DOES NOT respect sampling rates in the datadog agent + // https://docs.datadoghq.com/tracing/guide/trace_sampling_and_storage/#client-implementation + .value("_sampling_priority_v1", 1) .end if (parentId.nonEmpty) { diff --git a/reporters/kamon-datadog/src/main/scala/kamon/datadog/package.scala b/reporters/kamon-datadog/src/main/scala/kamon/datadog/package.scala index 76d24faa2..9f1c2ca7a 100644 --- a/reporters/kamon-datadog/src/main/scala/kamon/datadog/package.scala +++ b/reporters/kamon-datadog/src/main/scala/kamon/datadog/package.scala @@ -17,27 +17,34 @@ package kamon import java.nio.charset.StandardCharsets -import java.time.{ Duration, Instant } +import java.time.{Duration, Instant} import java.util.concurrent.TimeUnit import com.typesafe.config.Config import kamon.metric.MeasurementUnit -import kamon.metric.MeasurementUnit.{ information, time } +import kamon.metric.MeasurementUnit.{information, time} import okhttp3._ -import scala.util.{ Failure, Success, Try } +import scala.util.{Failure, Success, Try} package object datadog { implicit class InstantImprovements(val instant: Instant) { def getEpochNano: Long = { instant.getEpochSecond() * 1000000000 + - instant.getNano() + instant.getNano() } } - private[datadog] case class HttpClient(apiUrl: String, apiKey: Option[String], usingCompression: Boolean, usingAgent: Boolean, connectTimeout: Duration, - readTimeout: Duration, writeTimeout: Duration) { + private[datadog] case class HttpClient( + apiUrl: String, + apiKey: Option[String], + usingCompression: Boolean, + usingAgent: Boolean, + connectTimeout: Duration, + readTimeout: Duration, + writeTimeout: Duration + ) { val httpClient: OkHttpClient = createHttpClient() @@ -69,7 +76,9 @@ package object datadog { if (response.isSuccessful) { Success(responseBody) } else { - Failure(new Exception(s"Failed to ${method} metrics to Datadog with status code [${response.code()}], Body: [${responseBody}]")) + Failure(new Exception( + s"Failed to ${method} metrics to Datadog with status code [${response.code()}], Body: [${responseBody}]" + )) } case Failure(f) if f.getCause != null => Failure(f.getCause) diff --git a/reporters/kamon-datadog/src/test/scala/kamon/datadog/DatadogAPIReporterSpec.scala b/reporters/kamon-datadog/src/test/scala/kamon/datadog/DatadogAPIReporterSpec.scala index bb6991e7a..8676bb6c8 100644 --- a/reporters/kamon-datadog/src/test/scala/kamon/datadog/DatadogAPIReporterSpec.scala +++ b/reporters/kamon-datadog/src/test/scala/kamon/datadog/DatadogAPIReporterSpec.scala @@ -18,7 +18,8 @@ import scala.concurrent.ExecutionContext class DatadogAPIReporterSpec extends AbstractHttpReporter with Matchers with Reconfigure { "the DatadogAPIReporter" should { - val reporter = new DatadogAPIReporterFactory().create(ModuleFactory.Settings(Kamon.config(), ExecutionContext.global)) + val reporter = + new DatadogAPIReporterFactory().create(ModuleFactory.Settings(Kamon.config(), ExecutionContext.global)) val now = Instant.ofEpochMilli(1523395554) "sends metrics - compressed" in { @@ -47,7 +48,8 @@ class DatadogAPIReporterSpec extends AbstractHttpReporter with Matchers with Rec val request = server.takeRequest() - val decompressedBody = Okio.buffer(new InflaterSource(request.getBody.buffer(), new Inflater())).readByteString().utf8() + val decompressedBody = + Okio.buffer(new InflaterSource(request.getBody.buffer(), new Inflater())).readByteString().utf8() Json.parse(decompressedBody) shouldEqual Json .parse( @@ -122,7 +124,11 @@ class DatadogAPIReporterSpec extends AbstractHttpReporter with Matchers with Rec MetricSnapshot.ofDistributions( "test.timer", "test", - Metric.Settings.ForDistributionInstrument(MeasurementUnit.none, java.time.Duration.ZERO, DynamicRange.Default), + Metric.Settings.ForDistributionInstrument( + MeasurementUnit.none, + java.time.Duration.ZERO, + DynamicRange.Default + ), Instrument.Snapshot.apply(TagSet.Empty, distribution) :: Nil ) :: Nil, Nil diff --git a/reporters/kamon-datadog/src/test/scala/kamon/datadog/DatadogMetricSenderSpec.scala b/reporters/kamon-datadog/src/test/scala/kamon/datadog/DatadogMetricSenderSpec.scala index eada41e21..4a09ab976 100644 --- a/reporters/kamon-datadog/src/test/scala/kamon/datadog/DatadogMetricSenderSpec.scala +++ b/reporters/kamon-datadog/src/test/scala/kamon/datadog/DatadogMetricSenderSpec.scala @@ -28,7 +28,7 @@ import org.scalatest.wordspec.AnyWordSpec import java.time.Instant class DatadogMetricSenderSpec extends AnyWordSpec - with Matchers with Reconfigure { + with Matchers with Reconfigure { reconfigure => class TestBuffer extends PacketBuffer { @@ -37,7 +37,7 @@ class DatadogMetricSenderSpec extends AnyWordSpec override def flush(): Unit = {} override def appendMeasurement( - key: String, + key: String, measurementData: String ): Unit = { lst += (key -> measurementData) @@ -45,9 +45,11 @@ class DatadogMetricSenderSpec extends AnyWordSpec } "the DataDogMetricSender" should { - "send counter metrics" in AgentReporter(new TestBuffer(), ConfigFactory.parseString("kamon.environment.tags.env = staging").withFallback(Kamon.config())) { + "send counter metrics" in AgentReporter( + new TestBuffer(), + ConfigFactory.parseString("kamon.environment.tags.env = staging").withFallback(Kamon.config()) + ) { case (buffer, reporter) => - val now = Instant.now() reporter.reportPeriodSnapshot( PeriodSnapshot.apply( @@ -57,7 +59,8 @@ class DatadogMetricSenderSpec extends AnyWordSpec "test.counter", "test", Metric.Settings.ForValueInstrument(MeasurementUnit.none, java.time.Duration.ZERO), - Instrument.Snapshot.apply(TagSet.of("tag1", "value1"), 0L) :: Nil) :: Nil, + Instrument.Snapshot.apply(TagSet.of("tag1", "value1"), 0L) :: Nil + ) :: Nil, Nil, Nil, Nil, @@ -69,13 +72,16 @@ class DatadogMetricSenderSpec extends AnyWordSpec buffer.lst should contain("test.counter" -> "0|c|#service:kamon-application,env:staging,tag1:value1") } - "filter out environment tags" in AgentReporter(new TestBuffer(), ConfigFactory.parseString( - """ + "filter out environment tags" in AgentReporter( + new TestBuffer(), + ConfigFactory.parseString( + """ |kamon.datadog.environment-tags.exclude = [env] |kamon.environment.tags.env = staging - |""".stripMargin).withFallback(Kamon.config())) { + |""".stripMargin + ).withFallback(Kamon.config()) + ) { case (buffer, reporter) => - val now = Instant.now() reporter.reportPeriodSnapshot( PeriodSnapshot.apply( @@ -85,7 +91,8 @@ class DatadogMetricSenderSpec extends AnyWordSpec "test.counter", "test", Metric.Settings.ForValueInstrument(MeasurementUnit.none, java.time.Duration.ZERO), - Instrument.Snapshot.apply(TagSet.of("tag1", "value1"), 0L) :: Nil) :: Nil, + Instrument.Snapshot.apply(TagSet.of("tag1", "value1"), 0L) :: Nil + ) :: Nil, Nil, Nil, Nil, @@ -97,14 +104,17 @@ class DatadogMetricSenderSpec extends AnyWordSpec buffer.lst should contain("test.counter" -> "0|c|#service:kamon-application,tag1:value1") } - "filter other tags" in AgentReporter(new TestBuffer(), ConfigFactory.parseString( - """ + "filter other tags" in AgentReporter( + new TestBuffer(), + ConfigFactory.parseString( + """ |kamon.datadog.environment-tags.exclude = [] |kamon.datadog.environment-tags.filter.excludes = [ "tag*" ] |kamon.environment.tags.env = staging - |""".stripMargin).withFallback(Kamon.config())) { + |""".stripMargin + ).withFallback(Kamon.config()) + ) { case (buffer, reporter) => - val now = Instant.now() reporter.reportPeriodSnapshot( PeriodSnapshot.apply( @@ -114,7 +124,11 @@ class DatadogMetricSenderSpec extends AnyWordSpec "test.counter", "test", Metric.Settings.ForValueInstrument(MeasurementUnit.none, java.time.Duration.ZERO), - Instrument.Snapshot.apply(TagSet.of("tag1", "value1").withTag("tag2", "value2").withTag("otherTag", "otherValue"), 0L) :: Nil) :: Nil, + Instrument.Snapshot.apply( + TagSet.of("tag1", "value1").withTag("tag2", "value2").withTag("otherTag", "otherValue"), + 0L + ) :: Nil + ) :: Nil, Nil, Nil, Nil, @@ -126,13 +140,16 @@ class DatadogMetricSenderSpec extends AnyWordSpec buffer.lst should contain("test.counter" -> "0|c|#service:kamon-application,env:staging,otherTag:otherValue") } - "append no tags" in AgentReporter(new TestBuffer(), ConfigFactory.parseString( - """ + "append no tags" in AgentReporter( + new TestBuffer(), + ConfigFactory.parseString( + """ |kamon.datadog.environment-tags.include-service = no |kamon.datadog.environment-tags.exclude = [env] - |""".stripMargin).withFallback(Kamon.config())) { + |""".stripMargin + ).withFallback(Kamon.config()) + ) { case (buffer, reporter) => - val now = Instant.now() reporter.reportPeriodSnapshot( PeriodSnapshot.apply( @@ -142,7 +159,8 @@ class DatadogMetricSenderSpec extends AnyWordSpec "test.counter", "test", Metric.Settings.ForValueInstrument(MeasurementUnit.none, java.time.Duration.ZERO), - Instrument.Snapshot.apply(TagSet.Empty, 0L) :: Nil) :: Nil, + Instrument.Snapshot.apply(TagSet.Empty, 0L) :: Nil + ) :: Nil, Nil, Nil, Nil, diff --git a/reporters/kamon-datadog/src/test/scala/kamon/datadog/DatadogSpanReporterSpec.scala b/reporters/kamon-datadog/src/test/scala/kamon/datadog/DatadogSpanReporterSpec.scala index 2257fa0ae..129547096 100644 --- a/reporters/kamon-datadog/src/test/scala/kamon/datadog/DatadogSpanReporterSpec.scala +++ b/reporters/kamon-datadog/src/test/scala/kamon/datadog/DatadogSpanReporterSpec.scala @@ -57,7 +57,9 @@ trait TestData { ) val traceId128Bit = "13d350d23e4424d4" + contextSpan.trace.id.string - val spanWith128BitTraceId = span.copy(trace = Trace(Identifier(traceId128Bit, BigInt(traceId128Bit, 16).toByteArray), Trace.SamplingDecision.Sample)) + val spanWith128BitTraceId = span.copy(trace = + Trace(Identifier(traceId128Bit, BigInt(traceId128Bit, 16).toByteArray), Trace.SamplingDecision.Sample) + ) val json = Json.obj( "trace_id" -> BigDecimal(traceId), @@ -90,12 +92,15 @@ trait TestData { "error" -> 1 ) - val spanWithErrorTags = span.copy(tags = TagSet.from(Map( - "error" -> true, - "error.type" -> "RuntimeException", - "error.message" -> "Error message", - "error.stacktrace" -> "Error stacktrace" - )), hasError = true) + val spanWithErrorTags = span.copy( + tags = TagSet.from(Map( + "error" -> true, + "error.type" -> "RuntimeException", + "error.message" -> "Error message", + "error.stacktrace" -> "Error stacktrace" + )), + hasError = true + ) val jsonWithErrorTags = json ++ Json.obj( "meta" -> Json.obj( @@ -118,7 +123,7 @@ trait TestData { "false" -> false, "number" -> randomNumber.toString, "null" -> null, - //Default for span name + // Default for span name "component" -> "custom.component" ) ) @@ -136,9 +141,11 @@ trait TestData { ) ) - val spanWithMarks = span.copy(marks = Seq( - Span.Mark(from, "from") - )) + val spanWithMarks = span.copy(marks = + Seq( + Span.Mark(from, "from") + ) + ) val jsonWithMarks = json ++ Json.obj( "meta" -> Json.obj( @@ -173,17 +180,17 @@ trait TestData { "span with meta and marks" -> (Seq(spanWithTagsAndMarks), Json.arr(Json.arr(jsonWithTagsAndMarks))), "span with error" -> (Seq(spanWithError), Json.arr(Json.arr(jsonWithError))), "span with error tags" -> (Seq(spanWithErrorTags), Json.arr(Json.arr(jsonWithErrorTags))), - "multiple spans with same trace" -> (Seq(span, spanWithTags), Json.arr(Json.arr(json, jsonWithTags))) - // "multiple spans with two traces" -> (Seq(span, spanWithTags, otherTraceSpan, span), Json.arr(Json.arr(json, jsonWithTags, json), Json.arr(otherTraceJson))) + // "multiple spans with two traces" -> (Seq(span, spanWithTags, otherTraceSpan, span), Json.arr(Json.arr(json, jsonWithTags, json), Json.arr(otherTraceJson))) ) } class DatadogSpanReporterSpec extends AbstractHttpReporter with Matchers with Reconfigure { "the DatadogSpanReporter" should { - val reporter = new DatadogSpanReporterFactory().create(ModuleFactory.Settings(Kamon.config(), ExecutionContext.global)) - val testData = new TestData { } + val reporter = + new DatadogSpanReporterFactory().create(ModuleFactory.Settings(Kamon.config(), ExecutionContext.global)) + val testData = new TestData {} val (firstSpan, _) = testData.testMap.get("single span").head @@ -222,9 +229,12 @@ class DatadogSpanReporterSpec extends AbstractHttpReporter with Matchers with Re server.takeRequest() } - //it needs to be the last one :-( (takeRequest hangs after a timeout test) + // it needs to be the last one :-( (takeRequest hangs after a timeout test) s"ignore timed out responses" in { - val baseUrl = mockResponse("/test", new MockResponse().setStatus("HTTP/1.1 200 OK").setBody("OK").throttleBody(1, 6, TimeUnit.SECONDS)) + val baseUrl = mockResponse( + "/test", + new MockResponse().setStatus("HTTP/1.1 200 OK").setBody("OK").throttleBody(1, 6, TimeUnit.SECONDS) + ) applyConfig("kamon.datadog.trace.http.api-url = \"" + baseUrl + "\"") reporter.reconfigure(Kamon.config()) val exception = intercept[IOException] { diff --git a/reporters/kamon-graphite/src/main/scala/kamon/graphite/GraphiteReporter.scala b/reporters/kamon-graphite/src/main/scala/kamon/graphite/GraphiteReporter.scala index 52dccc581..fbf41e777 100644 --- a/reporters/kamon-graphite/src/main/scala/kamon/graphite/GraphiteReporter.scala +++ b/reporters/kamon-graphite/src/main/scala/kamon/graphite/GraphiteReporter.scala @@ -53,7 +53,10 @@ class GraphiteReporter extends MetricReporter { sender.reportPeriodSnapshot(snapshot) } catch { case e: Throwable => - log.warn(s"sending failed to ${reporterConfig.hostname}:${reporterConfig.port} - dispose current snapshot and retry sending next snapshot using a new connection", e) + log.warn( + s"sending failed to ${reporterConfig.hostname}:${reporterConfig.port} - dispose current snapshot and retry sending next snapshot using a new connection", + e + ) sender.close() sender = buildNewSender() } @@ -62,7 +65,15 @@ class GraphiteReporter extends MetricReporter { private def buildNewSender(): GraphiteSender = new GraphiteSender(reporterConfig) with TcpSender } -private case class GraphiteSenderConfig(hostname: String, port: Int, metricPrefix: String, legacySupport: Boolean, envTags: TagSet, tagFilter: Filter, percentiles: Seq[Double]) +private case class GraphiteSenderConfig( + hostname: String, + port: Int, + metricPrefix: String, + legacySupport: Boolean, + envTags: TagSet, + tagFilter: Filter, + percentiles: Seq[Double] +) private object GraphiteSenderConfig { def apply(config: Config): GraphiteSenderConfig = { val graphiteConfig = config.getConfig("kamon.graphite") @@ -107,7 +118,12 @@ private[graphite] abstract class GraphiteSender(val senderConfig: GraphiteSender senderConfig.percentiles.foreach { p => write(packetBuilder.build(metric.name, s"p$p", instrument.value.percentile(p).value, instrument.tags)) } - write(packetBuilder.build(metric.name, "average", average(instrument.value.sum, instrument.value.count), instrument.tags)) + write(packetBuilder.build( + metric.name, + "average", + average(instrument.value.sum, instrument.value.count), + instrument.tags + )) write(packetBuilder.build(metric.name, "sum", instrument.value.sum, instrument.tags)) } @@ -124,9 +140,10 @@ private class MetricPacketBuilder(baseName: String, timestamp: Long, config: Gra private val valueseperator = if (config.legacySupport) '.' else '=' private val reservedChars = Set(' ', tagseperator, valueseperator) - - def build(metricName: String, metricType: String, value: Long, metricTags: TagSet): Array[Byte] = build(metricName, metricType, value.toString, metricTags) - def build(metricName: String, metricType: String, value: Double, metricTags: TagSet): Array[Byte] = build(metricName, metricType, value.toString, metricTags) + def build(metricName: String, metricType: String, value: Long, metricTags: TagSet): Array[Byte] = + build(metricName, metricType, value.toString, metricTags) + def build(metricName: String, metricType: String, value: Double, metricTags: TagSet): Array[Byte] = + build(metricName, metricType, value.toString, metricTags) def build(metricName: String, metricType: String, value: String, metricTags: TagSet): Array[Byte] = { builder.setLength(0) builder.append(baseName).append(".").append(sanitize(metricName)).append(".").append(metricType) @@ -134,17 +151,18 @@ private class MetricPacketBuilder(baseName: String, timestamp: Long, config: Gra allTags.foreach(tag => if (config.tagFilter.accept(tag.key)) { builder - .append(tagseperator) - .append(sanitizeTag(tag.key)) - .append(valueseperator) - .append(sanitizeTag(Tag.unwrapValue(tag).toString)) - }) + .append(tagseperator) + .append(sanitizeTag(tag.key)) + .append(valueseperator) + .append(sanitizeTag(Tag.unwrapValue(tag).toString)) + } + ) builder - .append(" ") - .append(value) - .append(" ") - .append(timestamp) - .append("\n") + .append(" ") + .append(value) + .append(" ") + .append(timestamp) + .append("\n") val packet = builder.toString log.debug("built packet '{}'", packet) packet.getBytes(GraphiteSender.GraphiteEncoding) @@ -188,9 +206,9 @@ private trait TcpSender extends Sender { def flush(): Unit = out.foreach(_.flush()) def close(): Unit = { try - out.foreach {_.close()} + out.foreach { _.close() } catch { case t: Throwable => log.warn("failed to close connection", t) } } -} \ No newline at end of file +} diff --git a/reporters/kamon-graphite/src/test/scala/kamon/graphite/GraphiteReporterSpec.scala b/reporters/kamon-graphite/src/test/scala/kamon/graphite/GraphiteReporterSpec.scala index f76ce611c..e61ca8a30 100644 --- a/reporters/kamon-graphite/src/test/scala/kamon/graphite/GraphiteReporterSpec.scala +++ b/reporters/kamon-graphite/src/test/scala/kamon/graphite/GraphiteReporterSpec.scala @@ -27,9 +27,13 @@ class GraphiteReporterSpec extends AnyWordSpec with Matchers with BeforeAndAfter val to = Instant.ofEpochSecond(1517000993) val periodSnapshot = PeriodSnapshot.apply( - from, to, + from, + to, counters = List(MetricSnapshotBuilder.counter("custom.user.counter", TagSet.of("tag.1", "value.1.2"), 42)), - gauges = List.empty, histograms = List.empty, timers = List.empty, rangeSamplers = List.empty + gauges = List.empty, + histograms = List.empty, + timers = List.empty, + rangeSamplers = List.empty ) val lines = graphite.lineListener(1) @@ -38,7 +42,9 @@ class GraphiteReporterSpec extends AnyWordSpec with Matchers with BeforeAndAfter "send counter metrics to a server socket" in { reporter.reportPeriodSnapshot(periodSnapshot) - lines.awaitLines() shouldBe List("kamon-graphite.custom_user_counter.count;special-shouldsee-tag=bla;service=kamon-application;tag.1=value.1.2 42 1517000993") + lines.awaitLines() shouldBe List( + "kamon-graphite.custom_user_counter.count;special-shouldsee-tag=bla;service=kamon-application;tag.1=value.1.2 42 1517000993" + ) } reporter.stop() @@ -65,7 +71,8 @@ class GraphiteServer { } } -class GraphiteTcpSocketListener(port: Int, listeners: java.util.List[LineListener], started: CountDownLatch) extends Thread { +class GraphiteTcpSocketListener(port: Int, listeners: java.util.List[LineListener], started: CountDownLatch) + extends Thread { private val log = LoggerFactory.getLogger(classOf[GraphiteTcpSocketListener]) private val ss = new CopyOnWriteArrayList[InputStream] private val serverSocket = new ServerSocket() @@ -83,8 +90,7 @@ class GraphiteTcpSocketListener(port: Int, listeners: java.util.List[LineListene val line = lineReader.nextLine() listeners.asScala.foreach(_.putLine(line)) } - } - finally { + } finally { log.debug("stopping graphite simulator") serverSocket.close() } @@ -93,8 +99,7 @@ class GraphiteTcpSocketListener(port: Int, listeners: java.util.List[LineListene def close(): Unit = { try { ss.asScala.foreach(_.close()) - } - finally { + } finally { serverSocket.close() } } @@ -112,4 +117,4 @@ class LineListener(lineCount: Int) { counter.await(1, TimeUnit.SECONDS) lines.asScala.toList } -} \ No newline at end of file +} diff --git a/reporters/kamon-graphite/src/test/scala/kamon/graphite/GraphiteSenderSpec.scala b/reporters/kamon-graphite/src/test/scala/kamon/graphite/GraphiteSenderSpec.scala index 965159509..7e137c537 100644 --- a/reporters/kamon-graphite/src/test/scala/kamon/graphite/GraphiteSenderSpec.scala +++ b/reporters/kamon-graphite/src/test/scala/kamon/graphite/GraphiteSenderSpec.scala @@ -15,12 +15,21 @@ class GraphiteSenderSpec extends AnyWordSpec with Matchers with BeforeAndAfterAl val from = Instant.ofEpochSecond(1517000974) val to = Instant.ofEpochSecond(1517000993) - val senderConfig = GraphiteSenderConfig("hostX", 123, "kamon-graphiteprefix", legacySupport = false, TagSet.of("tag1", "111"), Filter.Accept, Seq(50.0, 90.0, 99.0)) + val senderConfig = GraphiteSenderConfig( + "hostX", + 123, + "kamon-graphiteprefix", + legacySupport = false, + TagSet.of("tag1", "111"), + Filter.Accept, + Seq(50.0, 90.0, 99.0) + ) "send counter metrics" in { - //arrange + // arrange val periodSnapshot = PeriodSnapshot( - from, to, + from, + to, counters = List(MetricSnapshotBuilder.counter("custom.user.counter", TagSet.Empty, 42)), gauges = List.empty, histograms = List.empty, @@ -29,17 +38,18 @@ class GraphiteSenderSpec extends AnyWordSpec with Matchers with BeforeAndAfterAl ) val testee = new TestGraphiteSender(senderConfig) - //act + // act testee.reportPeriodSnapshot(periodSnapshot) - //assert + // assert testee.messages shouldBe List("kamon-graphiteprefix.custom_user_counter.count;tag1=111 42 1517000993\n") } "send gauge metrics" in { - //arrange + // arrange val periodSnapshot = PeriodSnapshot( - from, to, + from, + to, counters = List.empty, gauges = List(MetricSnapshotBuilder.gauge("jvm.heap-size", TagSet.Empty, 150000000)), histograms = List.empty, @@ -48,17 +58,18 @@ class GraphiteSenderSpec extends AnyWordSpec with Matchers with BeforeAndAfterAl ) val testee = new TestGraphiteSender(senderConfig) - //act + // act testee.reportPeriodSnapshot(periodSnapshot) - //assert + // assert testee.messages shouldBe List("kamon-graphiteprefix.jvm_heap-size.value;tag1=111 1.5E8 1517000993\n") } "send histograms" in { - //arrange + // arrange val periodSnapshot = PeriodSnapshot( - from, to, + from, + to, counters = List.empty, gauges = List.empty, histograms = List(MetricSnapshotBuilder.histogram("my.histogram", TagSet.Empty)(1, 2, 4, 6)), @@ -67,10 +78,10 @@ class GraphiteSenderSpec extends AnyWordSpec with Matchers with BeforeAndAfterAl ) val testee = new TestGraphiteSender(senderConfig) - //act + // act testee.reportPeriodSnapshot(periodSnapshot) - //assert + // assert testee.messages shouldBe List( "kamon-graphiteprefix.my_histogram.count;tag1=111 4 1517000993\n", "kamon-graphiteprefix.my_histogram.min;tag1=111 1 1517000993\n", @@ -79,13 +90,15 @@ class GraphiteSenderSpec extends AnyWordSpec with Matchers with BeforeAndAfterAl "kamon-graphiteprefix.my_histogram.p90.0;tag1=111 6 1517000993\n", "kamon-graphiteprefix.my_histogram.p99.0;tag1=111 6 1517000993\n", "kamon-graphiteprefix.my_histogram.average;tag1=111 3 1517000993\n", - "kamon-graphiteprefix.my_histogram.sum;tag1=111 13 1517000993\n") + "kamon-graphiteprefix.my_histogram.sum;tag1=111 13 1517000993\n" + ) } "send timers" in { - //arrange + // arrange val periodSnapshot = PeriodSnapshot( - from, to, + from, + to, counters = List.empty, gauges = List.empty, histograms = List.empty, @@ -94,10 +107,10 @@ class GraphiteSenderSpec extends AnyWordSpec with Matchers with BeforeAndAfterAl ) val testee = new TestGraphiteSender(senderConfig) - //act + // act testee.reportPeriodSnapshot(periodSnapshot) - //assert + // assert testee.messages shouldBe List( "kamon-graphiteprefix.my_timer.count;tag1=111 4 1517000993\n", "kamon-graphiteprefix.my_timer.min;tag1=111 1 1517000993\n", @@ -106,13 +119,15 @@ class GraphiteSenderSpec extends AnyWordSpec with Matchers with BeforeAndAfterAl "kamon-graphiteprefix.my_timer.p90.0;tag1=111 6 1517000993\n", "kamon-graphiteprefix.my_timer.p99.0;tag1=111 6 1517000993\n", "kamon-graphiteprefix.my_timer.average;tag1=111 3 1517000993\n", - "kamon-graphiteprefix.my_timer.sum;tag1=111 13 1517000993\n") + "kamon-graphiteprefix.my_timer.sum;tag1=111 13 1517000993\n" + ) } "send ranges" in { - //arrange + // arrange val periodSnapshot = PeriodSnapshot( - from, to, + from, + to, counters = List.empty, gauges = List.empty, histograms = List.empty, @@ -121,10 +136,10 @@ class GraphiteSenderSpec extends AnyWordSpec with Matchers with BeforeAndAfterAl ) val testee = new TestGraphiteSender(senderConfig) - //act + // act testee.reportPeriodSnapshot(periodSnapshot) - //assert + // assert testee.messages shouldBe List( "kamon-graphiteprefix.my_range.count;tag1=111 4 1517000993\n", "kamon-graphiteprefix.my_range.min;tag1=111 1 1517000993\n", @@ -133,14 +148,20 @@ class GraphiteSenderSpec extends AnyWordSpec with Matchers with BeforeAndAfterAl "kamon-graphiteprefix.my_range.p90.0;tag1=111 6 1517000993\n", "kamon-graphiteprefix.my_range.p99.0;tag1=111 6 1517000993\n", "kamon-graphiteprefix.my_range.average;tag1=111 3 1517000993\n", - "kamon-graphiteprefix.my_range.sum;tag1=111 13 1517000993\n") + "kamon-graphiteprefix.my_range.sum;tag1=111 13 1517000993\n" + ) } "sanitize problematic tags" in { - //arrange + // arrange val periodSnapshot = PeriodSnapshot( - from, to, - counters = List(MetricSnapshotBuilder.counter("akka.actor.errors", TagSet.of("path", "as/user/actor").withTag("tag3", "333;3").withTag("tag2.123", 3L), 10)), + from, + to, + counters = List(MetricSnapshotBuilder.counter( + "akka.actor.errors", + TagSet.of("path", "as/user/actor").withTag("tag3", "333;3").withTag("tag2.123", 3L), + 10 + )), gauges = List.empty, histograms = List.empty, timers = List.empty, @@ -148,18 +169,25 @@ class GraphiteSenderSpec extends AnyWordSpec with Matchers with BeforeAndAfterAl ) val testee = new TestGraphiteSender(senderConfig) - //act + // act testee.reportPeriodSnapshot(periodSnapshot) - //assert - testee.messages(0) should be("kamon-graphiteprefix.akka_actor_errors.count;tag2.123=3;tag1=111;tag3=333_3;path=as/user/actor 10 1517000993\n") + // assert + testee.messages(0) should be( + "kamon-graphiteprefix.akka_actor_errors.count;tag2.123=3;tag1=111;tag3=333_3;path=as/user/actor 10 1517000993\n" + ) } "format tags as path for legacy tag support" in { - //arrange + // arrange val periodSnapshot = PeriodSnapshot( - from, to, - counters = List(MetricSnapshotBuilder.counter("akka.actor.errors", TagSet.of("path", "as/user/actor").withTag("tag3", "333;3").withTag("tag2.123", 3L), 10)), + from, + to, + counters = List(MetricSnapshotBuilder.counter( + "akka.actor.errors", + TagSet.of("path", "as/user/actor").withTag("tag3", "333;3").withTag("tag2.123", 3L), + 10 + )), gauges = List.empty, histograms = List.empty, timers = List.empty, @@ -167,11 +195,13 @@ class GraphiteSenderSpec extends AnyWordSpec with Matchers with BeforeAndAfterAl ) val testee = new TestGraphiteSender(senderConfig.copy(legacySupport = true)) - //act + // act testee.reportPeriodSnapshot(periodSnapshot) - //assert - testee.messages(0) should be("kamon-graphiteprefix.akka_actor_errors.count.tag2_123.3.tag1.111.tag3.333;3.path.as/user/actor 10 1517000993\n") + // assert + testee.messages(0) should be( + "kamon-graphiteprefix.akka_actor_errors.count.tag2_123.3.tag1.111.tag3.333;3.path.as/user/actor 10 1517000993\n" + ) } } @@ -182,4 +212,4 @@ private[graphite] class TestGraphiteSender(senderConfig: GraphiteSenderConfig) e override def write(data: Array[Byte]): Unit = messages = messages :+ new String(data, GraphiteSender.GraphiteEncoding) override def flush(): Unit = {} override def close(): Unit = {} -} \ No newline at end of file +} diff --git a/reporters/kamon-influxdb/src/main/scala/kamon/influxdb/InfluxDBReporter.scala b/reporters/kamon-influxdb/src/main/scala/kamon/influxdb/InfluxDBReporter.scala index 83070f50c..3c663e033 100644 --- a/reporters/kamon-influxdb/src/main/scala/kamon/influxdb/InfluxDBReporter.scala +++ b/reporters/kamon-influxdb/src/main/scala/kamon/influxdb/InfluxDBReporter.scala @@ -32,7 +32,6 @@ import org.slf4j.LoggerFactory import java.nio.charset.StandardCharsets.ISO_8859_1 import scala.util.Try - class InfluxDBReporterFactory extends ModuleFactory { override def create(settings: ModuleFactory.Settings): InfluxDBReporter = new InfluxDBReporter() } @@ -50,7 +49,7 @@ class InfluxDBReporter extends MetricReporter { Try { val response = client.newCall(request).execute() - if(response.isSuccessful()) { + if (response.isSuccessful()) { if (logger.isTraceEnabled()) { logger.trace("Successfully sent metrics to InfluxDB") } @@ -69,7 +68,6 @@ class InfluxDBReporter extends MetricReporter { } } - override def stop(): Unit = {} override def reconfigure(config: Config): Unit = { @@ -78,16 +76,16 @@ class InfluxDBReporter extends MetricReporter { } protected def getTimestamp(instant: Instant): String = { - settings.measurementPrecision match { - case "s" => - instant.getEpochSecond.toString - case "ms" => - instant.toEpochMilli.toString - case "u" | "µ" => - ((BigInt(instant.getEpochSecond) * 1000000) + TimeUnit.NANOSECONDS.toMicros(instant.getNano)).toString - case "ns" => - ((BigInt(instant.getEpochSecond) * 1000000000) + instant.getNano).toString - } + settings.measurementPrecision match { + case "s" => + instant.getEpochSecond.toString + case "ms" => + instant.toEpochMilli.toString + case "u" | "µ" => + ((BigInt(instant.getEpochSecond) * 1000000) + TimeUnit.NANOSECONDS.toMicros(instant.getNano)).toString + case "ns" => + ((BigInt(instant.getEpochSecond) * 1000000000) + instant.getNano).toString + } } private def translateToLineProtocol(periodSnapshot: PeriodSnapshot): RequestBody = { @@ -104,23 +102,38 @@ class InfluxDBReporter extends MetricReporter { RequestBody.create(MediaType.parse("text/plain"), builder.result()) } - private def writeLongMetricValue(builder: StringBuilder, metric: MetricSnapshot.Values[Long], fieldName: String, timestamp: String): Unit = { - metric.instruments.foreach{instrument => + private def writeLongMetricValue( + builder: StringBuilder, + metric: MetricSnapshot.Values[Long], + fieldName: String, + timestamp: String + ): Unit = { + metric.instruments.foreach { instrument => writeNameAndTags(builder, metric.name, instrument.tags) writeIntField(builder, fieldName, instrument.value, appendSeparator = false) writeTimestamp(builder, timestamp) } } - private def writeDoubleMetricValue(builder: StringBuilder, metric: MetricSnapshot.Values[Double], fieldName: String, timestamp: String): Unit = { - metric.instruments.foreach{instrument => + private def writeDoubleMetricValue( + builder: StringBuilder, + metric: MetricSnapshot.Values[Double], + fieldName: String, + timestamp: String + ): Unit = { + metric.instruments.foreach { instrument => writeNameAndTags(builder, metric.name, instrument.tags) writeDoubleField(builder, fieldName, instrument.value, appendSeparator = false) writeTimestamp(builder, timestamp) } } - private def writeMetricDistribution(builder: StringBuilder, metric: MetricSnapshot.Distributions, percentiles: Seq[Double], timestamp: String): Unit = { + private def writeMetricDistribution( + builder: StringBuilder, + metric: MetricSnapshot.Distributions, + percentiles: Seq[Double], + timestamp: String + ): Unit = { metric.instruments.foreach { instrument => if (instrument.value.count > 0) { writeNameAndTags(builder, metric.name, instrument.tags) @@ -144,9 +157,10 @@ class InfluxDBReporter extends MetricReporter { builder .append(escapeName(name)) - val tags = (if(settings.additionalTags.nonEmpty) metricTags.withTags(settings.additionalTags) else metricTags).all() + val tags = + (if (settings.additionalTags.nonEmpty) metricTags.withTags(settings.additionalTags) else metricTags).all() - if(tags.nonEmpty) { + if (tags.nonEmpty) { tags.foreach { t => if (settings.tagFilter.accept(t.key)) { builder @@ -169,19 +183,23 @@ class InfluxDBReporter extends MetricReporter { in.replace(" ", "\\ ") .replace(",", "\\,") - private def escapeString(in: String): String = in.replace(" ", "\\ ") .replace("=", "\\=") .replace(",", "\\,") - def writeDoubleField(builder: StringBuilder, fieldName: String, value: Double, appendSeparator: Boolean = true): Unit = { + def writeDoubleField( + builder: StringBuilder, + fieldName: String, + value: Double, + appendSeparator: Boolean = true + ): Unit = { builder .append(fieldName) .append('=') .append(String.valueOf(value)) - if(appendSeparator) + if (appendSeparator) builder.append(',') } @@ -192,7 +210,7 @@ class InfluxDBReporter extends MetricReporter { .append(String.valueOf(value)) .append('i') - if(appendSeparator) + if (appendSeparator) builder.append(',') } @@ -205,12 +223,14 @@ class InfluxDBReporter extends MetricReporter { protected def buildClient(settings: Settings): OkHttpClient = { val basicBuilder = new OkHttpClient.Builder() - val authenticator = settings.credentials.map(credentials => new Interceptor { - override def intercept(chain: Interceptor.Chain): Response = { - chain.proceed(chain.request().newBuilder().header("Authorization", credentials).build()) + val authenticator = settings.credentials.map(credentials => + new Interceptor { + override def intercept(chain: Interceptor.Chain): Response = { + chain.proceed(chain.request().newBuilder().header("Authorization", credentials).build()) + } } - }) - authenticator.foldLeft(basicBuilder){ case (builder, auth) => builder.addInterceptor(auth)}.build() + ) + authenticator.foldLeft(basicBuilder) { case (builder, auth) => builder.addInterceptor(auth) }.build() } } @@ -221,7 +241,7 @@ object InfluxDBReporter { credentials: Option[String], tagFilter: Filter, postEmptyDistributions: Boolean, - additionalTags:TagSet, + additionalTags: TagSet, measurementPrecision: String ) @@ -230,7 +250,7 @@ object InfluxDBReporter { val influxDBConfig = config.getConfig("kamon.influxdb") val host = influxDBConfig.getString("hostname") val credentials = if (influxDBConfig.hasPath("authentication")) { - if(influxDBConfig.hasPath("authentication.token")) + if (influxDBConfig.hasPath("authentication.token")) Some("Token " + influxDBConfig.getString("authentication.token")) else Some(Credentials.basic( @@ -247,8 +267,10 @@ object InfluxDBReporter { val precision = influxDBConfig.getString("precision") - if (!Set("ns","u","µ","ms","s").contains(precision)){ - throw new RuntimeException("Precision must be one of `[ns,u,µ,ms,s]` to match https://docs.influxdata.com/influxdb/v1.7/tools/api/#query-string-parameters-1") + if (!Set("ns", "u", "µ", "ms", "s").contains(precision)) { + throw new RuntimeException( + "Precision must be one of `[ns,u,µ,ms,s]` to match https://docs.influxdata.com/influxdb/v1.7/tools/api/#query-string-parameters-1" + ) } diff --git a/reporters/kamon-influxdb/src/test/scala/kamon/influxdb/InfluxDBCustomMatchers.scala b/reporters/kamon-influxdb/src/test/scala/kamon/influxdb/InfluxDBCustomMatchers.scala index f96caec46..62b14c90a 100644 --- a/reporters/kamon-influxdb/src/test/scala/kamon/influxdb/InfluxDBCustomMatchers.scala +++ b/reporters/kamon-influxdb/src/test/scala/kamon/influxdb/InfluxDBCustomMatchers.scala @@ -7,7 +7,6 @@ trait InfluxDBCustomMatchers { case class LineProtocol(measurement: String, tags: Seq[String], fields: Seq[String], timestamp: Option[String]) class LineProtocolMatcher(expectedPoint: String) extends Matcher[String] { - def apply(left: String) = { val leftLP = getLineProtocol(left) @@ -54,11 +53,11 @@ trait InfluxDBCustomMatchers { val measurementAndTags = parts(0).split(",").toList val (measurement, tags): (String, List[String]) = measurementAndTags match { - case x::xs => (x, xs) + case x :: xs => (x, xs) } val metric = parts(1).split(",") - val timestamp = if(parts(2).nonEmpty) Some(parts(2)) else None + val timestamp = if (parts(2).nonEmpty) Some(parts(2)) else None LineProtocol(measurement, tags, metric, timestamp) } diff --git a/reporters/kamon-influxdb/src/test/scala/kamon/influxdb/InfluxDBReporterSpec.scala b/reporters/kamon-influxdb/src/test/scala/kamon/influxdb/InfluxDBReporterSpec.scala index 7d5e386cc..2fbe4058c 100644 --- a/reporters/kamon-influxdb/src/test/scala/kamon/influxdb/InfluxDBReporterSpec.scala +++ b/reporters/kamon-influxdb/src/test/scala/kamon/influxdb/InfluxDBReporterSpec.scala @@ -37,7 +37,8 @@ class InfluxDBReporterSpec extends AnyWordSpec with Matchers with BeforeAndAfter ).withFallback(Kamon.config())) reporter.reportPeriodSnapshot(periodSnapshot) - val reportedLines = influxDB.takeRequest(10, TimeUnit.SECONDS).getBody.readString(Charset.forName("UTF-8")).split("\n") + val reportedLines = + influxDB.takeRequest(10, TimeUnit.SECONDS).getBody.readString(Charset.forName("UTF-8")).split("\n") val expectedLines = List( "custom.user.counter count=42i 1517000993", @@ -53,7 +54,7 @@ class InfluxDBReporterSpec extends AnyWordSpec with Matchers with BeforeAndAfter } "include the additional env tags if enabled" in { - //enable env tags + // enable env tags reporter.reconfigure(ConfigFactory.parseString( s""" |kamon.influxdb { @@ -69,7 +70,8 @@ class InfluxDBReporterSpec extends AnyWordSpec with Matchers with BeforeAndAfter ).withFallback(Kamon.config())) reporter.reportPeriodSnapshot(periodSnapshot) - val reportedLines = influxDB.takeRequest(10, TimeUnit.SECONDS).getBody.readString(Charset.forName("UTF-8")).split("\n") + val reportedLines = + influxDB.takeRequest(10, TimeUnit.SECONDS).getBody.readString(Charset.forName("UTF-8")).split("\n") val expectedLines = List( "custom.user.counter,service=test-service,host=test.host,instance=test-instance,env=staging,context=test-context count=42i 1517000993", @@ -104,7 +106,6 @@ class InfluxDBReporterSpec extends AnyWordSpec with Matchers with BeforeAndAfter rangeSamplers = MetricSnapshotBuilder.histogram("queue.monitor", TagSet.of("one", "tag"))(1, 2, 4, 6) :: Nil ) - override protected def beforeAll(): Unit = { influxDB.enqueue(new MockResponse().setResponseCode(204)) influxDB.enqueue(new MockResponse().setResponseCode(204)) @@ -132,7 +133,6 @@ class InfluxDBReporterSpec extends AnyWordSpec with Matchers with BeforeAndAfter ).withFallback(Kamon.config())) } - override protected def afterAll(): Unit = { influxDB.shutdown() } diff --git a/reporters/kamon-jaeger/src/main/scala/kamon/jaeger/JaegerClient.scala b/reporters/kamon-jaeger/src/main/scala/kamon/jaeger/JaegerClient.scala index fcb2dbaa8..33d2274a7 100644 --- a/reporters/kamon-jaeger/src/main/scala/kamon/jaeger/JaegerClient.scala +++ b/reporters/kamon-jaeger/src/main/scala/kamon/jaeger/JaegerClient.scala @@ -44,7 +44,7 @@ object JaegerClient { protocol match { case "udp" => buildAgentClient(host, port, includeEnvTags) case "http" | "https" => buildCollectorClient(httpUrl, includeEnvTags) - case anyOther => + case anyOther => log.warn("Unknown protocol [{}] found in the configuration, falling back to UDP", anyOther) buildAgentClient(host, port, includeEnvTags) } @@ -78,7 +78,8 @@ class JaegerSender(sender: ThriftSender, includeEnvTags: Boolean) { Kamon.environment.tags.iterator(_.toString) .map { p => new Tag(p.key, TagType.STRING).setVStr(p.value) } .toList - .asJava) + .asJava + ) /** * The overhead (in bytes) required for process information in every batch. @@ -86,7 +87,7 @@ class JaegerSender(sender: ThriftSender, includeEnvTags: Boolean) { val processOverhead = getSize(process) def sendSpans(spans: mutable.Buffer[JaegerSpan]): Unit = { - if(spans.nonEmpty) { + if (spans.nonEmpty) { Try(sender.send(process, spans.asJava)) match { case Failure(e) => log.warn(s"Reporting spans to jaeger failed. ${spans.size} spans discarded.", e) @@ -110,7 +111,7 @@ class JaegerSender(sender: ThriftSender, includeEnvTags: Boolean) { class JaegerClient(maxPacketSize: Option[Int], jaegerSender: JaegerSender) { def sendSpans(spans: Seq[Span.Finished]): Unit = { - if(maxPacketSize.isDefined) sendSpansBatched(spans, maxPacketSize.get) else sendAllSpans(spans) + if (maxPacketSize.isDefined) sendSpansBatched(spans, maxPacketSize.get) else sendAllSpans(spans) } private def sendAllSpans(spans: Seq[Span.Finished]): Unit = { @@ -120,11 +121,11 @@ class JaegerClient(maxPacketSize: Option[Int], jaegerSender: JaegerSender) { private def sendSpansBatched(spans: Seq[Span.Finished], maxPacketSize: Int): Unit = { var bufferBytes = 0 var buffer: mutable.Buffer[JaegerSpan] = mutable.Buffer() - for(kamonSpan <- spans) { + for (kamonSpan <- spans) { val span = JaegerSpanConverter.convertSpan(kamonSpan) val spanBytes = jaegerSender.getSize(span) - if(bufferBytes + spanBytes > maxPacketSize - jaegerSender.processOverhead) { + if (bufferBytes + spanBytes > maxPacketSize - jaegerSender.processOverhead) { jaegerSender.sendSpans(buffer) bufferBytes = 0 buffer = mutable.Buffer() @@ -137,4 +138,4 @@ class JaegerClient(maxPacketSize: Option[Int], jaegerSender: JaegerSender) { // Flush buffer by sending remaining spans jaegerSender.sendSpans(buffer) } -} \ No newline at end of file +} diff --git a/reporters/kamon-jaeger/src/main/scala/kamon/jaeger/JaegerReporter.scala b/reporters/kamon-jaeger/src/main/scala/kamon/jaeger/JaegerReporter.scala index b4e2b63ab..7aaa33e54 100644 --- a/reporters/kamon-jaeger/src/main/scala/kamon/jaeger/JaegerReporter.scala +++ b/reporters/kamon-jaeger/src/main/scala/kamon/jaeger/JaegerReporter.scala @@ -46,4 +46,3 @@ class JaegerReporter(@volatile private var jaegerClient: JaegerClient) extends S jaegerClient.sendSpans(spans) } } - diff --git a/reporters/kamon-newrelic/src/main/scala/kamon/newrelic/AttributeBuddy.scala b/reporters/kamon-newrelic/src/main/scala/kamon/newrelic/AttributeBuddy.scala index ae4320d28..cdb7c5cc4 100644 --- a/reporters/kamon-newrelic/src/main/scala/kamon/newrelic/AttributeBuddy.scala +++ b/reporters/kamon-newrelic/src/main/scala/kamon/newrelic/AttributeBuddy.scala @@ -46,8 +46,8 @@ object AttributeBuddy { private def putTypedValue(attributes: Attributes, key: String, value: Any) = { // Maintain the type of the tag value consistent with NR Attribute types value match { - case v: String => attributes.put(key, v) - case v: Number => attributes.put(key, v) + case v: String => attributes.put(key, v) + case v: Number => attributes.put(key, v) case v: Boolean => attributes.put(key, v) } } diff --git a/reporters/kamon-newrelic/src/main/scala/kamon/newrelic/NewRelicConfig.scala b/reporters/kamon-newrelic/src/main/scala/kamon/newrelic/NewRelicConfig.scala index 02d55a976..b7bc5e078 100644 --- a/reporters/kamon-newrelic/src/main/scala/kamon/newrelic/NewRelicConfig.scala +++ b/reporters/kamon-newrelic/src/main/scala/kamon/newrelic/NewRelicConfig.scala @@ -23,15 +23,14 @@ import kamon.newrelic.NewRelicConfig.NewRelicApiKey.{InsightsInsertKey, LicenseK import java.net.URL import java.time.Duration - private case class NewRelicConfig( - apiKey: NewRelicApiKey, - enableAuditLogging: Boolean, - userAgent: String, - callTimeout: Duration, - spanIngestUri: Option[URL], - metricIngestUri: Option[URL] - ) + apiKey: NewRelicApiKey, + enableAuditLogging: Boolean, + userAgent: String, + callTimeout: Duration, + spanIngestUri: Option[URL], + metricIngestUri: Option[URL] +) private object NewRelicConfig { @@ -41,7 +40,7 @@ private object NewRelicConfig { // TODO maybe some validation around these values? val apiKey = (nrConfig.getString("license-key"), nrConfig.getString("nr-insights-insert-key")) match { case (licenseKey, "none") if licenseKey != "none" => LicenseKey(licenseKey) - case (_, insightsInsertKey) => InsightsInsertKey(insightsInsertKey) + case (_, insightsInsertKey) => InsightsInsertKey(insightsInsertKey) } val enableAuditLogging = nrConfig.getBoolean("enable-audit-logging") @@ -58,13 +57,13 @@ private object NewRelicConfig { sealed trait NewRelicApiKey { def value: String = this match { - case LicenseKey(licenseKey) => licenseKey + case LicenseKey(licenseKey) => licenseKey case InsightsInsertKey(insightsInsertKey) => insightsInsertKey } def isLicenseKey: Boolean = this match { case LicenseKey(_) => true - case _ => false + case _ => false } } diff --git a/reporters/kamon-newrelic/src/main/scala/kamon/newrelic/metrics/ConversionSupport.scala b/reporters/kamon-newrelic/src/main/scala/kamon/newrelic/metrics/ConversionSupport.scala index 7b9436656..c5d57fb36 100644 --- a/reporters/kamon-newrelic/src/main/scala/kamon/newrelic/metrics/ConversionSupport.scala +++ b/reporters/kamon-newrelic/src/main/scala/kamon/newrelic/metrics/ConversionSupport.scala @@ -21,7 +21,7 @@ import kamon.metric.MetricSnapshot.Values object ConversionSupport { - def buildAttributes(metric: Values[_]) : Attributes = { + def buildAttributes(metric: Values[_]): Attributes = { val dimensionName = metric.settings.unit.dimension.name val magnitudeName = metric.settings.unit.magnitude.name val scaleFactor = metric.settings.unit.magnitude.scaleFactor diff --git a/reporters/kamon-newrelic/src/main/scala/kamon/newrelic/metrics/NewRelicCounters.scala b/reporters/kamon-newrelic/src/main/scala/kamon/newrelic/metrics/NewRelicCounters.scala index 12298a610..e4603c273 100644 --- a/reporters/kamon-newrelic/src/main/scala/kamon/newrelic/metrics/NewRelicCounters.scala +++ b/reporters/kamon-newrelic/src/main/scala/kamon/newrelic/metrics/NewRelicCounters.scala @@ -29,7 +29,13 @@ object NewRelicCounters { val attributes = buildAttributes(counter) logger.debug("name: {} ; numberOfInstruments: {}", counter.name, counter.instruments.size) counter.instruments.map { inst: Instrument.Snapshot[Long] => - new Count(counter.name, inst.value, start, end, addTagsFromTagSets(Seq(inst.tags), attributes.copy().put("sourceMetricType", "counter"))) + new Count( + counter.name, + inst.value, + start, + end, + addTagsFromTagSets(Seq(inst.tags), attributes.copy().put("sourceMetricType", "counter")) + ) } } } diff --git a/reporters/kamon-newrelic/src/main/scala/kamon/newrelic/metrics/NewRelicDistributionMetrics.scala b/reporters/kamon-newrelic/src/main/scala/kamon/newrelic/metrics/NewRelicDistributionMetrics.scala index 9d2f44374..3a087d694 100644 --- a/reporters/kamon-newrelic/src/main/scala/kamon/newrelic/metrics/NewRelicDistributionMetrics.scala +++ b/reporters/kamon-newrelic/src/main/scala/kamon/newrelic/metrics/NewRelicDistributionMetrics.scala @@ -44,12 +44,19 @@ object NewRelicDistributionMetrics { val buckets: Seq[Bucket] = distValue.buckets val summary: Summary = buildSummary(start, end, dist, instrumentBaseAttributes, distValue) - val percentiles: scala.Seq[_root_.com.newrelic.telemetry.metrics.Metric] = makePercentiles(dist.name, end, distValue, instrumentBaseAttributes) + val percentiles: scala.Seq[_root_.com.newrelic.telemetry.metrics.Metric] = + makePercentiles(dist.name, end, distValue, instrumentBaseAttributes) percentiles :+ summary } } - private def buildSummary(start: Long, end: Long, dist: Distributions, instrumentBaseAttributes: Attributes, distValue: Distribution) = { + private def buildSummary( + start: Long, + end: Long, + dist: Distributions, + instrumentBaseAttributes: Attributes, + distValue: Distribution + ) = { val count: Long = distValue.count val sum: Long = distValue.sum val min: Long = distValue.min @@ -57,7 +64,12 @@ object NewRelicDistributionMetrics { new Summary(dist.name + ".summary", count.toInt, sum, min, max, start, end, instrumentBaseAttributes) } - private def makePercentiles(name: String, end: Long, distValue: Distribution, instrumentBaseAttributes: Attributes): Seq[Metric] = { + private def makePercentiles( + name: String, + end: Long, + distValue: Distribution, + instrumentBaseAttributes: Attributes + ): Seq[Metric] = { percentilesToReport .map(rank => distValue.percentile(rank)) .filter(percentileValue => percentileValue != null) diff --git a/reporters/kamon-newrelic/src/main/scala/kamon/newrelic/metrics/NewRelicGauges.scala b/reporters/kamon-newrelic/src/main/scala/kamon/newrelic/metrics/NewRelicGauges.scala index 9fae7c995..7035b1c1d 100644 --- a/reporters/kamon-newrelic/src/main/scala/kamon/newrelic/metrics/NewRelicGauges.scala +++ b/reporters/kamon-newrelic/src/main/scala/kamon/newrelic/metrics/NewRelicGauges.scala @@ -29,7 +29,12 @@ object NewRelicGauges { val attributes = buildAttributes(gauge) logger.debug("name: {} ; numberOfInstruments: {}", gauge.name, gauge.instruments.size) gauge.instruments.map { inst: Instrument.Snapshot[Double] => - new Gauge(gauge.name, inst.value, timestamp, addTagsFromTagSets(Seq(inst.tags), attributes.copy().put("sourceMetricType", "gauge"))) + new Gauge( + gauge.name, + inst.value, + timestamp, + addTagsFromTagSets(Seq(inst.tags), attributes.copy().put("sourceMetricType", "gauge")) + ) } } diff --git a/reporters/kamon-newrelic/src/main/scala/kamon/newrelic/metrics/NewRelicMetricsReporter.scala b/reporters/kamon-newrelic/src/main/scala/kamon/newrelic/metrics/NewRelicMetricsReporter.scala index 31cf92fde..fdf89ab98 100644 --- a/reporters/kamon-newrelic/src/main/scala/kamon/newrelic/metrics/NewRelicMetricsReporter.scala +++ b/reporters/kamon-newrelic/src/main/scala/kamon/newrelic/metrics/NewRelicMetricsReporter.scala @@ -29,7 +29,8 @@ import org.slf4j.LoggerFactory import scala.collection.JavaConverters._ -class NewRelicMetricsReporter(senderBuilder: () => MetricBatchSender = () => NewRelicMetricsReporter.buildSender()) extends MetricReporter { +class NewRelicMetricsReporter(senderBuilder: () => MetricBatchSender = () => NewRelicMetricsReporter.buildSender()) + extends MetricReporter { private val logger = LoggerFactory.getLogger(classOf[NewRelicMetricsReporter]) @volatile private var commonAttributes = buildCommonAttributes(Kamon.environment) @@ -68,7 +69,7 @@ class NewRelicMetricsReporter(senderBuilder: () => MetricBatchSender = () => New reconfigure(Kamon.environment) } - //exposed for testing + // exposed for testing def reconfigure(environment: Environment): Unit = { commonAttributes = buildCommonAttributes(environment) sender = senderBuilder() diff --git a/reporters/kamon-newrelic/src/main/scala/kamon/newrelic/spans/NewRelicSpanConverter.scala b/reporters/kamon-newrelic/src/main/scala/kamon/newrelic/spans/NewRelicSpanConverter.scala index 1341f2fc0..b43807aab 100644 --- a/reporters/kamon-newrelic/src/main/scala/kamon/newrelic/spans/NewRelicSpanConverter.scala +++ b/reporters/kamon-newrelic/src/main/scala/kamon/newrelic/spans/NewRelicSpanConverter.scala @@ -59,7 +59,8 @@ object NewRelicSpanConverter { val remoteEndpoint = Endpoint( getStringTag(kamonSpan, PeerKeys.IPv4), getStringTag(kamonSpan, PeerKeys.IPv6), - getLongTag(kamonSpan, PeerKeys.Port).toInt) + getLongTag(kamonSpan, PeerKeys.Port).toInt + ) if (hasAnyData(remoteEndpoint)) { attributes.put("remoteEndpoint", remoteEndpoint.toString) @@ -79,7 +80,6 @@ object NewRelicSpanConverter { private def getLongTag(span: Span.Finished, tagName: String): Long = span.tags.get(longOption(tagName)).orElse(span.metricTags.get(longOption(tagName))).getOrElse(0L) - private def hasAnyData(endpoint: Endpoint): Boolean = endpoint.ipv4 != null || endpoint.ipv6 != null || endpoint.port != 0 diff --git a/reporters/kamon-newrelic/src/main/scala/kamon/newrelic/spans/NewRelicSpanReporter.scala b/reporters/kamon-newrelic/src/main/scala/kamon/newrelic/spans/NewRelicSpanReporter.scala index 14846b411..bd401bc11 100644 --- a/reporters/kamon-newrelic/src/main/scala/kamon/newrelic/spans/NewRelicSpanReporter.scala +++ b/reporters/kamon-newrelic/src/main/scala/kamon/newrelic/spans/NewRelicSpanReporter.scala @@ -28,7 +28,7 @@ import org.slf4j.LoggerFactory import scala.collection.JavaConverters._ class NewRelicSpanReporter(spanBatchSenderBuilder: SpanBatchSenderBuilder = - new SimpleSpanBatchSenderBuilder()) extends SpanReporter { + new SimpleSpanBatchSenderBuilder()) extends SpanReporter { private val logger = LoggerFactory.getLogger(classOf[NewRelicSpanReporter]) @volatile private var spanBatchSender = spanBatchSenderBuilder.build(Kamon.config()) @@ -41,8 +41,10 @@ class NewRelicSpanReporter(spanBatchSenderBuilder: SpanBatchSenderBuilder = def checkJoinParameter(): Unit = { val joinRemoteParentsWithSameID = Kamon.config().getBoolean("kamon.trace.join-remote-parents-with-same-span-id") if (!joinRemoteParentsWithSameID) { - logger.warn("For full distributed trace compatibility enable `kamon.trace.join-remote-parents-with-same-span-id` to " + - "preserve span id across client/server sides of a Span.") + logger.warn( + "For full distributed trace compatibility enable `kamon.trace.join-remote-parents-with-same-span-id` to " + + "preserve span id across client/server sides of a Span." + ) } } @@ -64,7 +66,7 @@ class NewRelicSpanReporter(spanBatchSenderBuilder: SpanBatchSenderBuilder = reconfigure(newConfig, Kamon.environment) } - //exposed for testing + // exposed for testing def reconfigure(newConfig: Config, environment: Environment): Unit = { logger.debug("NewRelicSpanReporter reconfigure...") spanBatchSender = spanBatchSenderBuilder.build(newConfig) @@ -83,4 +85,4 @@ object NewRelicSpanReporter { new NewRelicSpanReporter() } -} \ No newline at end of file +} diff --git a/reporters/kamon-newrelic/src/main/scala/kamon/newrelic/spans/SpanBatchSenderBuilder.scala b/reporters/kamon-newrelic/src/main/scala/kamon/newrelic/spans/SpanBatchSenderBuilder.scala index 3580fae66..76a549728 100644 --- a/reporters/kamon-newrelic/src/main/scala/kamon/newrelic/spans/SpanBatchSenderBuilder.scala +++ b/reporters/kamon-newrelic/src/main/scala/kamon/newrelic/spans/SpanBatchSenderBuilder.scala @@ -46,8 +46,10 @@ class SimpleSpanBatchSenderBuilder() extends SpanBatchSenderBuilder { def buildConfig(config: Config): SenderConfiguration = { val nrConfig = NewRelicConfig.fromConfig(config) if (nrConfig.apiKey == InsightsInsertKey("none")) { - logger.error("One of kamon.newrelic.license-key or kamon.newrelic.nr-insights-insert-key config settings should be defined. " + - "No spans will be sent to New Relic.") + logger.error( + "One of kamon.newrelic.license-key or kamon.newrelic.nr-insights-insert-key config settings should be defined. " + + "No spans will be sent to New Relic." + ) } val senderConfig = SpanBatchSender.configurationBuilder() .apiKey(nrConfig.apiKey.value) diff --git a/reporters/kamon-newrelic/src/test/scala/kamon/newrelic/AttributeBuddySpec.scala b/reporters/kamon-newrelic/src/test/scala/kamon/newrelic/AttributeBuddySpec.scala index bd6588391..63a46d637 100644 --- a/reporters/kamon-newrelic/src/test/scala/kamon/newrelic/AttributeBuddySpec.scala +++ b/reporters/kamon-newrelic/src/test/scala/kamon/newrelic/AttributeBuddySpec.scala @@ -13,7 +13,7 @@ import org.scalatest.wordspec.AnyWordSpec import scala.collection.JavaConverters._ -class AttributeBuddySpec extends AnyWordSpec with Matchers { +class AttributeBuddySpec extends AnyWordSpec with Matchers { "the tag set converter" should { "convert a tagset" in { val tags1 = TagSet.from(Map("foo" -> "bar", "boop" -> 1234L, "flower" -> false)) @@ -31,7 +31,8 @@ class AttributeBuddySpec extends AnyWordSpec with Matchers { "stringTag" -> "testThing", "numberTag" -> 234, "booleanTag" -> true, - "complexType" -> Map("lemon" -> "danishes").asJava).asJava) + "complexType" -> Map("lemon" -> "danishes").asJava + ).asJava) val result = AttributeBuddy.addTagsFromConfig(tagDetails.toConfig) val expected = new Attributes() diff --git a/reporters/kamon-newrelic/src/test/scala/kamon/newrelic/metrics/NewRelicCountersSpec.scala b/reporters/kamon-newrelic/src/test/scala/kamon/newrelic/metrics/NewRelicCountersSpec.scala index 83ab74016..53e5008ee 100644 --- a/reporters/kamon-newrelic/src/test/scala/kamon/newrelic/metrics/NewRelicCountersSpec.scala +++ b/reporters/kamon-newrelic/src/test/scala/kamon/newrelic/metrics/NewRelicCountersSpec.scala @@ -23,8 +23,10 @@ class NewRelicCountersSpec extends AnyWordSpec with Matchers { .put("foo", "bar") .put("sourceMetricType", "counter") - val expected1: NewRelicMetric = new Count("flib", TestMetricHelper.value1, TestMetricHelper.start, TestMetricHelper.end, expectedAttrs); - val expected2: NewRelicMetric = new Count("flib", TestMetricHelper.value2, TestMetricHelper.start, TestMetricHelper.end, expectedAttrs); + val expected1: NewRelicMetric = + new Count("flib", TestMetricHelper.value1, TestMetricHelper.start, TestMetricHelper.end, expectedAttrs); + val expected2: NewRelicMetric = + new Count("flib", TestMetricHelper.value2, TestMetricHelper.start, TestMetricHelper.end, expectedAttrs); val expectedResult: Seq[NewRelicMetric] = Seq(expected1, expected2) diff --git a/reporters/kamon-newrelic/src/test/scala/kamon/newrelic/metrics/NewRelicDistributionMetricsSpec.scala b/reporters/kamon-newrelic/src/test/scala/kamon/newrelic/metrics/NewRelicDistributionMetricsSpec.scala index 821f9ae4c..fdcaebe38 100644 --- a/reporters/kamon-newrelic/src/test/scala/kamon/newrelic/metrics/NewRelicDistributionMetricsSpec.scala +++ b/reporters/kamon-newrelic/src/test/scala/kamon/newrelic/metrics/NewRelicDistributionMetricsSpec.scala @@ -26,7 +26,16 @@ class NewRelicDistributionMetricsSpec extends AnyWordSpec with Matchers { .put("twelve", "bishop") .put("dimension", "information") .put("sourceMetricType", "mountain") - val summary = new Summary("trev.summary", 44, 101.0, 13.0, 17.0, TestMetricHelper.start, TestMetricHelper.end, summaryAttributes) + val summary = new Summary( + "trev.summary", + 44, + 101.0, + 13.0, + 17.0, + TestMetricHelper.start, + TestMetricHelper.end, + summaryAttributes + ) val gaugeAttributes = summaryAttributes.copy().put("percentile", 90.0d) val gauge = new Gauge("trev.percentiles", 2.0, TestMetricHelper.end, gaugeAttributes) val expectedMetrics = Seq(gauge, summary) diff --git a/reporters/kamon-newrelic/src/test/scala/kamon/newrelic/metrics/NewRelicMetricsReporterSpec.scala b/reporters/kamon-newrelic/src/test/scala/kamon/newrelic/metrics/NewRelicMetricsReporterSpec.scala index 9e8731e37..cca0f4d48 100644 --- a/reporters/kamon-newrelic/src/test/scala/kamon/newrelic/metrics/NewRelicMetricsReporterSpec.scala +++ b/reporters/kamon-newrelic/src/test/scala/kamon/newrelic/metrics/NewRelicMetricsReporterSpec.scala @@ -70,25 +70,51 @@ class NewRelicMetricsReporterSpec extends AnyWordSpec with Matchers { .put("dimension", "information") .put("sourceMetricType", "rangeSampler") - private val count1: Metric = new Count("flib", TestMetricHelper.value1, TestMetricHelper.start, TestMetricHelper.end, countAttributes) - private val count2: Metric = new Count("flib", TestMetricHelper.value2, TestMetricHelper.start, TestMetricHelper.end, countAttributes) + private val count1: Metric = + new Count("flib", TestMetricHelper.value1, TestMetricHelper.start, TestMetricHelper.end, countAttributes) + private val count2: Metric = + new Count("flib", TestMetricHelper.value2, TestMetricHelper.start, TestMetricHelper.end, countAttributes) private val gauge: Metric = new Gauge("shirley", 15.6d, TestMetricHelper.end, gaugeAttributes) - private val histogramGauge: Metric = new Gauge("trev.percentiles", 2.0, TestMetricHelper.end, - histogramSummaryAttributes.copy().put("percentile", 90.0d)) - private val histogramSummary: Metric = new Summary("trev.summary", 44, 101.0, 13.0, 17.0, - TestMetricHelper.start, TestMetricHelper.end, histogramSummaryAttributes) - - private val rangeSamplerGauge: Metric = new Gauge("ranger.percentiles", 8.0, TestMetricHelper.end, - rangeSamplerAttributes.copy().put("percentile", 95.0d)) - private val rangeSamplerSummary: Metric = new Summary("ranger.summary", 88, 202.0, 26.0, 34.0, - TestMetricHelper.start, TestMetricHelper.end, rangeSamplerAttributes) - - private val timerGauge: Metric = new Gauge("timer.percentiles", 4.0, TestMetricHelper.end, - timerSummaryAttributes.copy().put("percentile", 95.0d)) - private val timerSummary: Metric = new Summary("timer.summary", 88, 202.0, 26.0, 34.0, - TestMetricHelper.start, TestMetricHelper.end, timerSummaryAttributes) + private val histogramGauge: Metric = + new Gauge("trev.percentiles", 2.0, TestMetricHelper.end, histogramSummaryAttributes.copy().put("percentile", 90.0d)) + private val histogramSummary: Metric = new Summary( + "trev.summary", + 44, + 101.0, + 13.0, + 17.0, + TestMetricHelper.start, + TestMetricHelper.end, + histogramSummaryAttributes + ) + + private val rangeSamplerGauge: Metric = + new Gauge("ranger.percentiles", 8.0, TestMetricHelper.end, rangeSamplerAttributes.copy().put("percentile", 95.0d)) + private val rangeSamplerSummary: Metric = new Summary( + "ranger.summary", + 88, + 202.0, + 26.0, + 34.0, + TestMetricHelper.start, + TestMetricHelper.end, + rangeSamplerAttributes + ) + + private val timerGauge: Metric = + new Gauge("timer.percentiles", 4.0, TestMetricHelper.end, timerSummaryAttributes.copy().put("percentile", 95.0d)) + private val timerSummary: Metric = new Summary( + "timer.summary", + 88, + 202.0, + 26.0, + 34.0, + TestMetricHelper.start, + TestMetricHelper.end, + timerSummaryAttributes + ) "The metrics reporter" should { "send some metrics" in { @@ -97,8 +123,15 @@ class NewRelicMetricsReporterSpec extends AnyWordSpec with Matchers { val histogram = TestMetricHelper.buildHistogramDistribution val timer = TestMetricHelper.buildTimerDistribution val rangeSampler = TestMetricHelper.buildRangeSamplerDistribution - val periodSnapshot = new PeriodSnapshot(TestMetricHelper.startInstant, TestMetricHelper.endInstant, - Seq(counter), Seq(kamonGauge), Seq(histogram), Seq(timer), Seq(rangeSampler)) + val periodSnapshot = new PeriodSnapshot( + TestMetricHelper.startInstant, + TestMetricHelper.endInstant, + Seq(counter), + Seq(kamonGauge), + Seq(histogram), + Seq(timer), + Seq(rangeSampler) + ) val expectedCommonAttributes: Attributes = new Attributes() .put("service.name", "kamon-application") @@ -106,8 +139,20 @@ class NewRelicMetricsReporterSpec extends AnyWordSpec with Matchers { .put("host.hostname", InetAddress.getLocalHost.getHostName) .put("testTag", "testValue") val expectedBatch: MetricBatch = - new MetricBatch(Seq(count1, count2, gauge, histogramGauge, histogramSummary, timerGauge, timerSummary, rangeSamplerGauge, rangeSamplerSummary).asJava, - expectedCommonAttributes) + new MetricBatch( + Seq( + count1, + count2, + gauge, + histogramGauge, + histogramSummary, + timerGauge, + timerSummary, + rangeSamplerGauge, + rangeSamplerSummary + ).asJava, + expectedCommonAttributes + ) val sender = mock(classOf[MetricBatchSender]) @@ -121,18 +166,27 @@ class NewRelicMetricsReporterSpec extends AnyWordSpec with Matchers { val counter = TestMetricHelper.buildCounter val kamonGauge = TestMetricHelper.buildGauge val histogram = TestMetricHelper.buildHistogramDistribution - val periodSnapshot = new PeriodSnapshot(TestMetricHelper.startInstant, TestMetricHelper.endInstant, - Seq(counter), Seq(kamonGauge), Seq(histogram), Seq(), Seq()) + val periodSnapshot = new PeriodSnapshot( + TestMetricHelper.startInstant, + TestMetricHelper.endInstant, + Seq(counter), + Seq(kamonGauge), + Seq(histogram), + Seq(), + Seq() + ) val expectedCommonAttributes: Attributes = new Attributes() .put("service.name", "cheese-whiz") .put("instrumentation.provider", "kamon-agent") .put("testTag", "testThing") .put("host.hostname", "thing") - val expectedBatch: MetricBatch = new MetricBatch(Seq(count1, count2, gauge, histogramGauge, histogramSummary).asJava, expectedCommonAttributes) + val expectedBatch: MetricBatch = + new MetricBatch(Seq(count1, count2, gauge, histogramGauge, histogramSummary).asJava, expectedCommonAttributes) val tagDetails = ConfigValueFactory.fromMap(Map("testTag" -> "testThing").asJava) - val configObject: ConfigValue = ConfigValueFactory.fromMap(Map("service" -> "cheese-whiz", "host" -> "thing", "tags" -> tagDetails).asJava) + val configObject: ConfigValue = + ConfigValueFactory.fromMap(Map("service" -> "cheese-whiz", "host" -> "thing", "tags" -> tagDetails).asJava) val config: Config = Kamon.config().withValue("kamon.environment", configObject) val sender = mock(classOf[MetricBatchSender]) @@ -179,7 +233,6 @@ class NewRelicMetricsReporterSpec extends AnyWordSpec with Matchers { assert(!result.useLicenseKey) } - "default the url when config not provided" in { val result = createSenderConfiguration(Map("nr-insights-insert-key" -> "secret")) assert(new URL("https://metric-api.newrelic.com/metric/v1") == result.getEndpointUrl) diff --git a/reporters/kamon-newrelic/src/test/scala/kamon/newrelic/metrics/TestMetricHelper.scala b/reporters/kamon-newrelic/src/test/scala/kamon/newrelic/metrics/TestMetricHelper.scala index 8b984ad14..0ad95b19b 100644 --- a/reporters/kamon-newrelic/src/test/scala/kamon/newrelic/metrics/TestMetricHelper.scala +++ b/reporters/kamon-newrelic/src/test/scala/kamon/newrelic/metrics/TestMetricHelper.scala @@ -35,7 +35,9 @@ object TestMetricHelper { def buildGauge = { val tagSet: TagSet = TagSet.from(Map("foo" -> "bar")) val settings = Metric.Settings.ForValueInstrument( - new MeasurementUnit(Dimension.Information, new MeasurementUnit.Magnitude("finch", 11.0d)), Duration.ofMillis(12)) + new MeasurementUnit(Dimension.Information, new MeasurementUnit.Magnitude("finch", 11.0d)), + Duration.ofMillis(12) + ) val inst = new Instrument.Snapshot[Double](tagSet, 15.6d) new MetricSnapshot.Values[Double]("shirley", "another one", settings, Seq(inst)) } @@ -44,10 +46,14 @@ object TestMetricHelper { val tagSet: TagSet = TagSet.from(Map("twelve" -> "bishop")) val dynamicRange: DynamicRange = DynamicRange.Default val settings = Metric.Settings.ForDistributionInstrument( - new MeasurementUnit(Dimension.Information, metric.MeasurementUnit.Magnitude("eimer", 603.3d)), Duration.ofMillis(12), dynamicRange) + new MeasurementUnit(Dimension.Information, metric.MeasurementUnit.Magnitude("eimer", 603.3d)), + Duration.ofMillis(12), + dynamicRange + ) val percentiles = Map(90d -> Percentage(90d, 2L, 816L), 87d -> Percentage(87d, 2L, 816L)) - val distribution: Distribution = buildHistogramDist(Percentage(19d, 2L, 816L), Bucket(717L, 881L), Distro(13L, 17L, 101L, 44L), percentiles) + val distribution: Distribution = + buildHistogramDist(Percentage(19d, 2L, 816L), Bucket(717L, 881L), Distro(13L, 17L, 101L, 44L), percentiles) val inst: Snapshot[Distribution] = new Snapshot[Distribution](tagSet, distribution) new metric.MetricSnapshot.Distributions("trev", "a good trevor", settings, Seq(inst)) } @@ -56,9 +62,13 @@ object TestMetricHelper { val tagSet: TagSet = TagSet.from(Map("thirteen" -> "queen")) val dynamicRange: DynamicRange = DynamicRange.Default val settings = Metric.Settings.ForDistributionInstrument( - new MeasurementUnit(Dimension.Information, new metric.MeasurementUnit.Magnitude("timer", 333.3d)), Duration.ofMillis(15), dynamicRange) + new MeasurementUnit(Dimension.Information, new metric.MeasurementUnit.Magnitude("timer", 333.3d)), + Duration.ofMillis(15), + dynamicRange + ) val percentiles = Map(95d -> Percentage(95d, 4L, 1632L), 87d -> Percentage(87d, 2L, 816L)) - val distribution: Distribution = buildHistogramDist(Percentage(38d, 4L, 1632L), Bucket(1424L, 1672L), Distro(26L, 34L, 202L, 88L), percentiles) + val distribution: Distribution = + buildHistogramDist(Percentage(38d, 4L, 1632L), Bucket(1424L, 1672L), Distro(26L, 34L, 202L, 88L), percentiles) val inst: Snapshot[Distribution] = new Snapshot[Distribution](tagSet, distribution) new metric.MetricSnapshot.Distributions("timer", "a good timer", settings, Seq(inst)) } @@ -67,9 +77,13 @@ object TestMetricHelper { val tagSet: TagSet = TagSet.from(Map("eleven" -> "elevenses")) val dynamicRange: DynamicRange = DynamicRange.Default val settings = Metric.Settings.ForDistributionInstrument( - new MeasurementUnit(Dimension.Information, new metric.MeasurementUnit.Magnitude("home", 333.3d)), Duration.ofMillis(15), dynamicRange) + new MeasurementUnit(Dimension.Information, new metric.MeasurementUnit.Magnitude("home", 333.3d)), + Duration.ofMillis(15), + dynamicRange + ) val percentiles = Map(95d -> Percentage(95d, 8L, 1632L), 87d -> Percentage(87d, 4L, 816L)) - val distribution: Distribution = buildHistogramDist(Percentage(38d, 4L, 1632L), Bucket(1424L, 1672L), Distro(26L, 34L, 202L, 88L), percentiles) + val distribution: Distribution = + buildHistogramDist(Percentage(38d, 4L, 1632L), Bucket(1424L, 1672L), Distro(26L, 34L, 202L, 88L), percentiles) val inst: Snapshot[Distribution] = new Snapshot[Distribution](tagSet, distribution) new metric.MetricSnapshot.Distributions("ranger", "baby's first range sampler", settings, Seq(inst)) } @@ -98,7 +112,12 @@ object TestMetricHelper { case class Distro(min: Long, max: Long, sum: Long, count: Long) - private def buildHistogramDist(perc: Percentage, bucket: Bucket, distro: Distro, percentileValues: Map[Double, Percentage]) = { + private def buildHistogramDist( + perc: Percentage, + bucket: Bucket, + distro: Distro, + percentileValues: Map[Double, Percentage] + ) = { val distribution: Distribution = new Distribution() { override def dynamicRange: DynamicRange = DynamicRange.Default @@ -111,7 +130,8 @@ object TestMetricHelper { override def count: Long = distro.count - override def percentile(rank: Double): Distribution.Percentile = percentileValues.get(rank).map(r => r.toPercentile).orNull + override def percentile(rank: Double): Distribution.Percentile = + percentileValues.get(rank).map(r => r.toPercentile).orNull override def percentiles: Seq[Distribution.Percentile] = Seq(perc.toPercentile) diff --git a/reporters/kamon-newrelic/src/test/scala/kamon/newrelic/spans/NewRelicSpanReporterSpec.scala b/reporters/kamon-newrelic/src/test/scala/kamon/newrelic/spans/NewRelicSpanReporterSpec.scala index be9271172..5cd385d14 100644 --- a/reporters/kamon-newrelic/src/test/scala/kamon/newrelic/spans/NewRelicSpanReporterSpec.scala +++ b/reporters/kamon-newrelic/src/test/scala/kamon/newrelic/spans/NewRelicSpanReporterSpec.scala @@ -46,9 +46,10 @@ class NewRelicSpanReporterSpec extends AnyWordSpec with Matchers { when(builder.build(any[Config])).thenReturn(sender) val reporter = new NewRelicSpanReporter(builder) - //change the service name attribute and tags and make sure that we reconfigure with it! + // change the service name attribute and tags and make sure that we reconfigure with it! val tagDetails = ConfigValueFactory.fromMap(Map("testTag" -> "testThing").asJava) - val configObject: ConfigValue = ConfigValueFactory.fromMap(Map("service" -> "cheese-whiz", "host" -> "thing", "tags" -> tagDetails).asJava) + val configObject: ConfigValue = + ConfigValueFactory.fromMap(Map("service" -> "cheese-whiz", "host" -> "thing", "tags" -> tagDetails).asJava) val config: Config = Kamon.config().withValue("kamon.environment", configObject) reporter.reconfigure(config, Environment("thing", "cheese-whiz", null, null, TagSet.of("testTag", "testThing"))) @@ -61,7 +62,11 @@ class NewRelicSpanReporterSpec extends AnyWordSpec with Matchers { } } - private def buildExpectedBatch(serviceName: String = "kamon-application", hostName : String = InetAddress.getLocalHost.getHostName, tagValue: String = "testValue" ) = { + private def buildExpectedBatch( + serviceName: String = "kamon-application", + hostName: String = InetAddress.getLocalHost.getHostName, + tagValue: String = "testValue" + ) = { val expectedAttributes = new Attributes() .put("xx", TestSpanHelper.now) .put("span.kind", "client") diff --git a/reporters/kamon-newrelic/src/test/scala/kamon/newrelic/spans/TestSpanHelper.scala b/reporters/kamon-newrelic/src/test/scala/kamon/newrelic/spans/TestSpanHelper.scala index 383bee4ea..2a1565063 100644 --- a/reporters/kamon-newrelic/src/test/scala/kamon/newrelic/spans/TestSpanHelper.scala +++ b/reporters/kamon-newrelic/src/test/scala/kamon/newrelic/spans/TestSpanHelper.scala @@ -21,7 +21,12 @@ object TestSpanHelper { val traceId = "nineohtwooneoh" val parentId = "pppppppppppppppp21" - def makeKamonSpan(kind: Kind, id: String = spanId, tags: TagSet = TagSet.of("foo", "bar"), hasError: Boolean = false) = { + def makeKamonSpan( + kind: Kind, + id: String = spanId, + tags: TagSet = TagSet.of("foo", "bar"), + hasError: Boolean = false + ) = { val kamonSpan = Span.Finished( id = Identifier(id, Array[Byte](2)), trace = Trace(Identifier(traceId, Array[Byte](1)), SamplingDecision.Sample), diff --git a/reporters/kamon-opentelemetry/src/main/scala/kamon/otel/OpenTelemetryTraceReporter.scala b/reporters/kamon-opentelemetry/src/main/scala/kamon/otel/OpenTelemetryTraceReporter.scala index f6f914538..0a78de2e7 100644 --- a/reporters/kamon-opentelemetry/src/main/scala/kamon/otel/OpenTelemetryTraceReporter.scala +++ b/reporters/kamon-opentelemetry/src/main/scala/kamon/otel/OpenTelemetryTraceReporter.scala @@ -54,35 +54,44 @@ import OpenTelemetryTraceReporter._ /** * Converts internal finished Kamon spans to OpenTelemetry format and sends to a configured OpenTelemetry endpoint using gRPC. */ -class OpenTelemetryTraceReporter(traceServiceFactory: Config => TraceService)(implicit ec: ExecutionContext) extends SpanReporter { +class OpenTelemetryTraceReporter(traceServiceFactory: Config => TraceService)(implicit ec: ExecutionContext) + extends SpanReporter { private var traceService: Option[TraceService] = None private var spanConverterFunc: Seq[Span.Finished] => JCollection[SpanData] = (_ => new util.ArrayList[SpanData](0)) override def reportSpans(spans: Seq[Span.Finished]): Unit = { if (spans.nonEmpty) { - traceService.foreach(ts => ts.exportSpans(spanConverterFunc(spans)).onComplete { - case Success(_) => logger.debug("Successfully exported traces") - - //TODO is there result for which a retry is relevant? Perhaps a glitch in the receiving service - //Keeping logs to debug as the underlying exporter will log if it fails to export traces, and the failure isn't surfaced in the response anyway - case Failure(t) => logger.debug("Failed to export traces", t) - }) + traceService.foreach(ts => + ts.exportSpans(spanConverterFunc(spans)).onComplete { + case Success(_) => logger.debug("Successfully exported traces") + + // TODO is there result for which a retry is relevant? Perhaps a glitch in the receiving service + // Keeping logs to debug as the underlying exporter will log if it fails to export traces, and the failure isn't surfaced in the response anyway + case Failure(t) => logger.debug("Failed to export traces", t) + } + ) } } override def reconfigure(newConfig: Config): Unit = { logger.info("Reconfigure OpenTelemetry Trace Reporter") - //pre-generate the function for converting Kamon span to proto span + // pre-generate the function for converting Kamon span to proto span val attributes: Map[String, String] = newConfig.getString("kamon.otel.attributes").split(',').filter(_ contains '=').map(_.trim.split("=", 2)).map { case Array(k, v) => val decoded = Try(URLDecoder.decode(v.trim, "UTF-8")) - decoded.failed.foreach(t => throw new IllegalArgumentException(s"value for attribute ${k.trim} is not a url-encoded string", t)) + decoded.failed.foreach(t => + throw new IllegalArgumentException(s"value for attribute ${k.trim} is not a url-encoded string", t) + ) k.trim -> decoded.get }.toMap val resource: Resource = buildResource(attributes) - this.spanConverterFunc = SpanConverter.convert(newConfig.getBoolean("kamon.otel.trace.include-error-event"), resource, kamonSettings.version) + this.spanConverterFunc = SpanConverter.convert( + newConfig.getBoolean("kamon.otel.trace.include-error-event"), + resource, + kamonSettings.version + ) this.traceService = Option(traceServiceFactory.apply(newConfig)) } @@ -109,11 +118,11 @@ class OpenTelemetryTraceReporter(traceServiceFactory: Config => TraceService)(im .put("telemetry.sdk.version", kamonSettings.version) attributes.foreach { case (k, v) => builder.put(k, v) } - //add all kamon.environment.tags as KeyValues to the Resource object + // add all kamon.environment.tags as KeyValues to the Resource object env.tags.iterator().foreach { - case t: Tag.String => builder.put(t.key, t.value) + case t: Tag.String => builder.put(t.key, t.value) case t: Tag.Boolean => builder.put(t.key, t.value) - case t: Tag.Long => builder.put(t.key, t.value) + case t: Tag.Long => builder.put(t.key, t.value) } builder.build() diff --git a/reporters/kamon-opentelemetry/src/main/scala/kamon/otel/SpanConverter.scala b/reporters/kamon-opentelemetry/src/main/scala/kamon/otel/SpanConverter.scala index 1af560ddc..897ea0a9a 100644 --- a/reporters/kamon-opentelemetry/src/main/scala/kamon/otel/SpanConverter.scala +++ b/reporters/kamon-opentelemetry/src/main/scala/kamon/otel/SpanConverter.scala @@ -32,22 +32,31 @@ import kamon.trace.Span.{Kind, TagKeys} import kamon.trace.Trace.SamplingDecision.Sample import kamon.trace.{Identifier, Span} - -class SpanWrapper(includeErrorEvent: Boolean, resource: Resource, kamonVersion: String, span: Span.Finished) extends SpanData { +class SpanWrapper(includeErrorEvent: Boolean, resource: Resource, kamonVersion: String, span: Span.Finished) + extends SpanData { private val instrumentationScopeInfo: InstrumentationScopeInfo = - InstrumentationScopeInfo.create(span.metricTags.get(Lookups.option(Span.TagKeys.Component)) getOrElse "kamon-instrumentation", kamonVersion, null) + InstrumentationScopeInfo.create( + span.metricTags.get(Lookups.option(Span.TagKeys.Component)) getOrElse "kamon-instrumentation", + kamonVersion, + null + ) private val sampled: Boolean = span.trace.samplingDecision == Sample private val attachErrorEvent: Boolean = includeErrorEvent && span.hasError private def getErrorEvent: Seq[EventData] = if (attachErrorEvent) { val builder = Attributes.builder() - span.tags.get(Lookups.option(TagKeys.ErrorMessage)).foreach(msg => builder.put(AttributeKey.stringKey("exception.message"), msg)) - span.tags.get(Lookups.option(TagKeys.ErrorStacktrace)).foreach(st => builder.put(AttributeKey.stringKey("exception.stacktrace"), st)) - span.tags.get(Lookups.option(TagKeys.ErrorType)).foreach(st => builder.put(AttributeKey.stringKey("exception.type"), st)) + span.tags.get(Lookups.option(TagKeys.ErrorMessage)).foreach(msg => + builder.put(AttributeKey.stringKey("exception.message"), msg) + ) + span.tags.get(Lookups.option(TagKeys.ErrorStacktrace)).foreach(st => + builder.put(AttributeKey.stringKey("exception.stacktrace"), st) + ) + span.tags.get(Lookups.option(TagKeys.ErrorType)).foreach(st => + builder.put(AttributeKey.stringKey("exception.type"), st) + ) Seq(EventData.create(SpanConverter.toEpocNano(span.from), "exception", builder.build)) - } - else Nil + } else Nil override def getName: String = span.operationName @@ -56,7 +65,8 @@ class SpanWrapper(includeErrorEvent: Boolean, resource: Resource, kamonVersion: override val getSpanContext: SpanContext = SpanConverter.mkSpanContext(sampled, span.trace.id, span.id) override val getParentSpanContext: SpanContext = - if (span.parentId.isEmpty) SpanContext.getInvalid else SpanConverter.mkSpanContext(sampled, span.trace.id, span.parentId) + if (span.parentId.isEmpty) SpanContext.getInvalid + else SpanConverter.mkSpanContext(sampled, span.trace.id, span.parentId) override val getStatus: StatusData = SpanConverter.getStatus(span) @@ -94,12 +104,12 @@ private[otel] object SpanConverter { TimeUnit.NANOSECONDS.convert(instant.getEpochSecond, TimeUnit.SECONDS) + instant.getNano private[otel] def toKind(kind: Span.Kind): SpanKind = kind match { - case Kind.Client => SpanKind.CLIENT + case Kind.Client => SpanKind.CLIENT case Kind.Consumer => SpanKind.CONSUMER case Kind.Internal => SpanKind.INTERNAL case Kind.Producer => SpanKind.PRODUCER - case Kind.Server => SpanKind.SERVER - case _ => SpanKind.INTERNAL // Default value + case Kind.Server => SpanKind.SERVER + case _ => SpanKind.INTERNAL // Default value } private[otel] def getTraceFlags(sample: Boolean): TraceFlags = @@ -125,9 +135,9 @@ private[otel] object SpanConverter { private[otel] def toAttributes(tags: TagSet): Attributes = { val builder = Attributes.builder() tags.iterator().foreach { - case t: Tag.String => builder.put(t.key, t.value) + case t: Tag.String => builder.put(t.key, t.value) case t: Tag.Boolean => builder.put(t.key, t.value) - case t: Tag.Long => builder.put(t.key, t.value) + case t: Tag.Long => builder.put(t.key, t.value) } builder.build() } @@ -135,6 +145,10 @@ private[otel] object SpanConverter { def convertSpan(includeErrorEvent: Boolean, resource: Resource, kamonVersion: String)(span: Span.Finished): SpanData = new SpanWrapper(includeErrorEvent, resource, kamonVersion, span) - def convert(includeErrorEvent: Boolean, resource: Resource, kamonVersion: String)(spans: Seq[Span.Finished]): JCollection[SpanData] = + def convert( + includeErrorEvent: Boolean, + resource: Resource, + kamonVersion: String + )(spans: Seq[Span.Finished]): JCollection[SpanData] = spans.map(convertSpan(includeErrorEvent, resource, kamonVersion)).asJava } diff --git a/reporters/kamon-opentelemetry/src/main/scala/kamon/otel/TraceService.scala b/reporters/kamon-opentelemetry/src/main/scala/kamon/otel/TraceService.scala index 1909b5619..96915ada7 100644 --- a/reporters/kamon-opentelemetry/src/main/scala/kamon/otel/TraceService.scala +++ b/reporters/kamon-opentelemetry/src/main/scala/kamon/otel/TraceService.scala @@ -29,7 +29,6 @@ import io.opentelemetry.sdk.trace.`export`.SpanExporter import io.opentelemetry.sdk.trace.data.SpanData import org.slf4j.LoggerFactory - /** * Service for exporting OpenTelemetry traces */ @@ -52,7 +51,8 @@ private[otel] object OtlpTraceService { def apply(config: Config): TraceService = { val otelExporterConfig = config.getConfig("kamon.otel.trace") val endpoint = otelExporterConfig.getString("endpoint") - val fullEndpoint = if (otelExporterConfig.hasPath("full-endpoint")) Some(otelExporterConfig.getString("full-endpoint")) else None + val fullEndpoint = + if (otelExporterConfig.hasPath("full-endpoint")) Some(otelExporterConfig.getString("full-endpoint")) else None val compression = otelExporterConfig.getString("compression") match { case "gzip" => true case x => @@ -61,13 +61,13 @@ private[otel] object OtlpTraceService { } val protocol = otelExporterConfig.getString("protocol") match { case "http/protobuf" => "http/protobuf" - case "grpc" => "grpc" + case "grpc" => "grpc" case x => logger.warn(s"Unrecognised opentelemetry schema type $x. Defaulting to grpc") "grpc" } val headers = otelExporterConfig.getString("headers").split(',').filter(_.nonEmpty).map(_.split("=", 2)).map { - case Array(k) => k -> "" + case Array(k) => k -> "" case Array(k, v) => k -> v }.toSeq val timeout = otelExporterConfig.getDuration("timeout") @@ -79,8 +79,8 @@ private[otel] object OtlpTraceService { // Seems to be some dispute as to whether the / should technically be added in the case that the base path doesn't // include it. Adding because it's probably what's desired most of the time, and can always be overridden by full-endpoint case ("http/protobuf", None) => if (endpoint.endsWith("/")) endpoint + "v1/traces" else endpoint + "/v1/traces" - case (_, Some(full)) => full - case (_, None) => endpoint + case (_, Some(full)) => full + case (_, None) => endpoint } logger.info(s"Configured endpoint for OpenTelemetry trace reporting [$url] using $protocol protocol") @@ -89,15 +89,23 @@ private[otel] object OtlpTraceService { } } -private[otel] class OtlpTraceService(protocol: String, endpoint: String, compressionEnabled: Boolean, headers: Seq[(String, String)], timeout: Duration) extends TraceService { +private[otel] class OtlpTraceService( + protocol: String, + endpoint: String, + compressionEnabled: Boolean, + headers: Seq[(String, String)], + timeout: Duration +) extends TraceService { private val compressionMethod = if (compressionEnabled) "gzip" else "none" private val delegate: SpanExporter = protocol match { case "grpc" => - val builder = OtlpGrpcSpanExporter.builder().setEndpoint(endpoint).setCompression(compressionMethod).setTimeout(timeout) + val builder = + OtlpGrpcSpanExporter.builder().setEndpoint(endpoint).setCompression(compressionMethod).setTimeout(timeout) headers.foreach { case (k, v) => builder.addHeader(k, v) } builder.build() case "http/protobuf" => - val builder = OtlpHttpSpanExporter.builder().setEndpoint(endpoint).setCompression(compressionMethod).setTimeout(timeout) + val builder = + OtlpHttpSpanExporter.builder().setEndpoint(endpoint).setCompression(compressionMethod).setTimeout(timeout) headers.foreach { case (k, v) => builder.addHeader(k, v) } builder.build() } diff --git a/reporters/kamon-opentelemetry/src/test/scala/kamon/otel/OpenTelemetryTraceReporterSpec.scala b/reporters/kamon-opentelemetry/src/test/scala/kamon/otel/OpenTelemetryTraceReporterSpec.scala index f2b8186f3..6e7b2f90b 100644 --- a/reporters/kamon-opentelemetry/src/test/scala/kamon/otel/OpenTelemetryTraceReporterSpec.scala +++ b/reporters/kamon-opentelemetry/src/test/scala/kamon/otel/OpenTelemetryTraceReporterSpec.scala @@ -52,25 +52,41 @@ class OpenTelemetryTraceReporterSpec extends AnyWordSpec with Matchers with Opti val (reporter, traceService) = openTelemetryTraceReporter() val span = finishedSpan() reporter.reportSpans(Seq(span)) - //there should be a single span reported + // there should be a single span reported traceService.exportTraceServiceRequest.value.size() shouldEqual 1 val spanData = traceService.exportTraceServiceRequest.value.iterator().next() val kamonVersion = Kamon.status().settings().version - spanData.getResource.getAttributes.asMap().asScala should contain(AttributeKey.stringKey("service.name"), "kamon-test-application") - spanData.getResource.getAttributes.asMap().asScala should contain(AttributeKey.stringKey("telemetry.sdk.name"), "kamon") - spanData.getResource.getAttributes.asMap().asScala should contain(AttributeKey.stringKey("telemetry.sdk.language"), "scala") - spanData.getResource.getAttributes.asMap().asScala should contain(AttributeKey.stringKey("telemetry.sdk.version"), kamonVersion) - spanData.getResource.getAttributes.asMap().asScala should contain(AttributeKey.stringKey("service.version"), "x.x.x") + spanData.getResource.getAttributes.asMap().asScala should contain( + AttributeKey.stringKey("service.name"), + "kamon-test-application" + ) + spanData.getResource.getAttributes.asMap().asScala should contain( + AttributeKey.stringKey("telemetry.sdk.name"), + "kamon" + ) + spanData.getResource.getAttributes.asMap().asScala should contain( + AttributeKey.stringKey("telemetry.sdk.language"), + "scala" + ) + spanData.getResource.getAttributes.asMap().asScala should contain( + AttributeKey.stringKey("telemetry.sdk.version"), + kamonVersion + ) + spanData.getResource.getAttributes.asMap().asScala should contain( + AttributeKey.stringKey("service.version"), + "x.x.x" + ) spanData.getResource.getAttributes.asMap().asScala should contain(AttributeKey.stringKey("env"), "kamon-devint") spanData.getResource.getAttributes.asMap().asScala should contain(AttributeKey.stringKey("att1"), "v1") spanData.getResource.getAttributes.asMap().asScala should contain(AttributeKey.stringKey("att2"), "v2") spanData.getResource.getAttributes.asMap().asScala should contain(AttributeKey.stringKey("att3"), " a=b,c=d ") val host = spanData.getResource.getAttributes.asMap().asScala.get(AttributeKey.stringKey("host.name")) host shouldBe defined - val instance = spanData.getResource.getAttributes.asMap().asScala.get(AttributeKey.stringKey("service.instance.id")) + val instance = + spanData.getResource.getAttributes.asMap().asScala.get(AttributeKey.stringKey("service.instance.id")) instance should contain(s"kamon-test-application@${host.get}") - //assert instrumentation labels + // assert instrumentation labels val instrumentationScopeInfo = spanData.getInstrumentationScopeInfo instrumentationScopeInfo.getName should be("kamon-instrumentation") instrumentationScopeInfo.getVersion should be(kamonVersion) @@ -86,11 +102,12 @@ class OpenTelemetryTraceReporterSpec extends AnyWordSpec with Matchers with Opti val (reporter, traceService) = openTelemetryTraceReporter() reporter.stop() traceService.hasBeenClosed should be(true) - reporter.stop() //stopping a second time should not matter + reporter.stop() // stopping a second time should not matter } "building instance with the factory should work" in { - val reporter = new OpenTelemetryTraceReporter.Factory().create(ModuleFactory.Settings(config, ExecutionContext.global)) + val reporter = + new OpenTelemetryTraceReporter.Factory().create(ModuleFactory.Settings(config, ExecutionContext.global)) reporter.stop() } diff --git a/reporters/kamon-opentelemetry/src/test/scala/kamon/otel/SpanConverterSpec.scala b/reporters/kamon-opentelemetry/src/test/scala/kamon/otel/SpanConverterSpec.scala index b406e3d74..585b468db 100644 --- a/reporters/kamon-opentelemetry/src/test/scala/kamon/otel/SpanConverterSpec.scala +++ b/reporters/kamon-opentelemetry/src/test/scala/kamon/otel/SpanConverterSpec.scala @@ -92,12 +92,14 @@ class SpanConverterSpec extends AnyWordSpec with Matchers with Utils { "constructing a valid SpanContext" should { "work with an 8 byte traceid" in { - val spanContext = SpanConverter.mkSpanContext(true, Factory.EightBytesIdentifier.generate(), spanIDFactory.generate()) + val spanContext = + SpanConverter.mkSpanContext(true, Factory.EightBytesIdentifier.generate(), spanIDFactory.generate()) SpanId.isValid(spanContext.getSpanId) shouldEqual true TraceId.isValid(spanContext.getTraceId) shouldEqual true } "work with a 16 byte traceid" in { - val spanContext = SpanConverter.mkSpanContext(true, Factory.SixteenBytesIdentifier.generate(), spanIDFactory.generate()) + val spanContext = + SpanConverter.mkSpanContext(true, Factory.SixteenBytesIdentifier.generate(), spanIDFactory.generate()) SpanId.isValid(spanContext.getSpanId) shouldEqual true TraceId.isValid(spanContext.getTraceId) shouldEqual true } @@ -105,7 +107,10 @@ class SpanConverterSpec extends AnyWordSpec with Matchers with Utils { "should convert an Instant into nanos since EPOC" in { val now = System.currentTimeMillis() - SpanConverter.toEpocNano(Instant.ofEpochMilli(now)) shouldBe TimeUnit.NANOSECONDS.convert(now, TimeUnit.MILLISECONDS) + SpanConverter.toEpocNano(Instant.ofEpochMilli(now)) shouldBe TimeUnit.NANOSECONDS.convert( + now, + TimeUnit.MILLISECONDS + ) SpanConverter.toEpocNano(Instant.ofEpochMilli(100)) shouldBe 100 * 1000000 } @@ -139,16 +144,28 @@ class SpanConverterSpec extends AnyWordSpec with Matchers with Utils { "result in a valid ResourceSpans" in { val kamonSpan = finishedSpan(TagSet.of(Span.TagKeys.Component, "some-instrumentation-library")) val resourceSpans = SpanConverter.convert(false, resource, kamonVersion)(Seq(kamonSpan)).asScala - //there should be a single span reported + // there should be a single span reported resourceSpans.size shouldEqual 1 - //assert resource labels - resourceSpans.head.getResource.getAttributes.asMap().asScala should contain(AttributeKey.stringKey("service.name"), "TestService") - resourceSpans.head.getResource.getAttributes.asMap().asScala should contain(AttributeKey.stringKey("telemetry.sdk.name"), "kamon") - resourceSpans.head.getResource.getAttributes.asMap().asScala should contain(AttributeKey.stringKey("telemetry.sdk.language"), "scala") - resourceSpans.head.getResource.getAttributes.asMap().asScala should contain(AttributeKey.stringKey("telemetry.sdk.version"), "0.0.0") + // assert resource labels + resourceSpans.head.getResource.getAttributes.asMap().asScala should contain( + AttributeKey.stringKey("service.name"), + "TestService" + ) + resourceSpans.head.getResource.getAttributes.asMap().asScala should contain( + AttributeKey.stringKey("telemetry.sdk.name"), + "kamon" + ) + resourceSpans.head.getResource.getAttributes.asMap().asScala should contain( + AttributeKey.stringKey("telemetry.sdk.language"), + "scala" + ) + resourceSpans.head.getResource.getAttributes.asMap().asScala should contain( + AttributeKey.stringKey("telemetry.sdk.version"), + "0.0.0" + ) val scopeInfo = resourceSpans.head.getInstrumentationScopeInfo - //assert instrumentation labels + // assert instrumentation labels scopeInfo.getName should be("some-instrumentation-library") scopeInfo.getVersion should be("0.0.0") scopeInfo.getSchemaUrl should be(null) @@ -157,7 +174,7 @@ class SpanConverterSpec extends AnyWordSpec with Matchers with Utils { instInfo.getName should be("some-instrumentation-library") instInfo.getVersion should be("0.0.0") - //assert span contents + // assert span contents compareSpans(kamonSpan, resourceSpans.head) } } @@ -168,9 +185,9 @@ class SpanConverterSpec extends AnyWordSpec with Matchers with Utils { val keyValues = actual.getAttributes expected.tags.all().foreach { - case t: Tag.String => keyValues.asMap().asScala should contain(AttributeKey.stringKey(t.key) -> t.value) + case t: Tag.String => keyValues.asMap().asScala should contain(AttributeKey.stringKey(t.key) -> t.value) case t: Tag.Boolean => keyValues.asMap().asScala should contain(AttributeKey.booleanKey(t.key) -> t.value) - case t: Tag.Long => keyValues.asMap().asScala should contain(AttributeKey.longKey(t.key) -> t.value) + case t: Tag.Long => keyValues.asMap().asScala should contain(AttributeKey.longKey(t.key) -> t.value) } } } diff --git a/reporters/kamon-opentelemetry/src/test/scala/kamon/otel/TraceServiceSpec.scala b/reporters/kamon-opentelemetry/src/test/scala/kamon/otel/TraceServiceSpec.scala index ec874409c..dc2c7da49 100644 --- a/reporters/kamon-opentelemetry/src/test/scala/kamon/otel/TraceServiceSpec.scala +++ b/reporters/kamon-opentelemetry/src/test/scala/kamon/otel/TraceServiceSpec.scala @@ -27,7 +27,8 @@ import org.scalatest.wordspec.AnyWordSpec * Tests for the [[TraceService]] */ class TraceServiceSpec extends AnyWordSpec with Matchers with ScalaFutures with Utils { - private implicit val defaultPatience: PatienceConfig = PatienceConfig(timeout = Span(2, Seconds), interval = Span(15, Millis)) + private implicit val defaultPatience: PatienceConfig = + PatienceConfig(timeout = Span(2, Seconds), interval = Span(15, Millis)) private val resource = Resource.builder() .put("service.name", "TestService") @@ -42,7 +43,7 @@ class TraceServiceSpec extends AnyWordSpec with Matchers with ScalaFutures with "fail in case the remote service is not operable" in { val traceService = OtlpTraceService(config) - //the actual data does not really matter as this will fail due to connection issues + // the actual data does not really matter as this will fail due to connection issues val resources = SpanConverter.convert(false, resource, kamonVersion)(Seq(finishedSpan())) val f = traceService.exportSpans(resources) whenReady(f.failed, Timeout(Span.apply(12, Seconds))) { e => diff --git a/reporters/kamon-prometheus/src/main/scala/kamon/prometheus/HttpClient.scala b/reporters/kamon-prometheus/src/main/scala/kamon/prometheus/HttpClient.scala index 094417ec0..7c6930cec 100644 --- a/reporters/kamon-prometheus/src/main/scala/kamon/prometheus/HttpClient.scala +++ b/reporters/kamon-prometheus/src/main/scala/kamon/prometheus/HttpClient.scala @@ -52,12 +52,14 @@ class HttpClient(val apiUrl: String, connectTimeout: Duration, readTimeout: Dura if (response.isSuccessful) { Success(responseBody) } else { - Failure(new Exception(s"Failed to $method metrics to Prometheus Pushgateway with status code [${response.code()}], " - + s"Body: [$responseBody]")) + Failure( + new Exception(s"Failed to $method metrics to Prometheus Pushgateway with status code [${response.code()}], " + + s"Body: [$responseBody]") + ) } case Failure(f) if f.getCause != null => Failure(f.getCause) - case f@Failure(_) => + case f @ Failure(_) => f.asInstanceOf[Try[String]] } } diff --git a/reporters/kamon-prometheus/src/main/scala/kamon/prometheus/MetricOverrideReporter.scala b/reporters/kamon-prometheus/src/main/scala/kamon/prometheus/MetricOverrideReporter.scala index 15a3df763..7eebfc6a7 100644 --- a/reporters/kamon-prometheus/src/main/scala/kamon/prometheus/MetricOverrideReporter.scala +++ b/reporters/kamon-prometheus/src/main/scala/kamon/prometheus/MetricOverrideReporter.scala @@ -35,7 +35,8 @@ class MetricOverrideReporter(wrappedReporter: MetricReporter, config: Config = K timers = snapshot.timers.map(updateDistribution), rangeSamplers = snapshot.rangeSamplers.map(updateDistribution), gauges = snapshot.gauges.map(updateDistribution), - counters = snapshot.counters.map(updateDistribution)) + counters = snapshot.counters.map(updateDistribution) + ) wrappedReporter.reportPeriodSnapshot(updatedSnapshot) } @@ -52,7 +53,7 @@ class MetricOverrideReporter(wrappedReporter: MetricReporter, config: Config = K val remappedTags = TagSet.builder() tags.iterator().foreach(tag => { - if(!mapping.tagsToDelete.contains(tag.key)) { + if (!mapping.tagsToDelete.contains(tag.key)) { remappedTags.add(mapping.tagsToRename.getOrElse(tag.key, tag.key), Tag.unwrapValue(tag).toString) } }) @@ -63,7 +64,8 @@ class MetricOverrideReporter(wrappedReporter: MetricReporter, config: Config = K private def updateDistribution[T <: Metric.Settings, U](metric: MetricSnapshot[T, U]): MetricSnapshot[T, U] = { metricsMap.get(metric.name).map(mapping => { - val mappedInstruments = if(mapping.tagsToRename.isEmpty && mapping.tagsToDelete.isEmpty) metric.instruments else { + val mappedInstruments = if (mapping.tagsToRename.isEmpty && mapping.tagsToDelete.isEmpty) metric.instruments + else { metric.instruments.map(inst => { inst.copy(tags = remapTags(inst.tags, mapping)) }) @@ -92,15 +94,21 @@ class MetricOverrideReporter(wrappedReporter: MetricReporter, config: Config = K val mappingConfig = config.getConfig("kamon.prometheus.metric-overrides") mappingConfig.configurations.map { case (name, config) => - (name, MetricMapping( - if (config.hasPath("name")) - Some(config.getString("name")) else None, - if (config.hasPath("delete-tags")) - config.getStringList("delete-tags").asScala.toSet else Set.empty, - if (config.hasPath("rename-tags")) - config.getObject("rename-tags").unwrapped().asScala.toMap - .map { case (tagName, value) => (tagName, value.toString) } else Map.empty - )) + ( + name, + MetricMapping( + if (config.hasPath("name")) + Some(config.getString("name")) + else None, + if (config.hasPath("delete-tags")) + config.getStringList("delete-tags").asScala.toSet + else Set.empty, + if (config.hasPath("rename-tags")) + config.getObject("rename-tags").unwrapped().asScala.toMap + .map { case (tagName, value) => (tagName, value.toString) } + else Map.empty + ) + ) } } diff --git a/reporters/kamon-prometheus/src/main/scala/kamon/prometheus/PrometheusPushgatewayReporter.scala b/reporters/kamon-prometheus/src/main/scala/kamon/prometheus/PrometheusPushgatewayReporter.scala index 3eefe7f26..221a2a7b3 100644 --- a/reporters/kamon-prometheus/src/main/scala/kamon/prometheus/PrometheusPushgatewayReporter.scala +++ b/reporters/kamon-prometheus/src/main/scala/kamon/prometheus/PrometheusPushgatewayReporter.scala @@ -25,13 +25,14 @@ import kamon.module.{MetricReporter, Module, ModuleFactory} import org.slf4j.LoggerFactory class PrometheusPushgatewayReporter( - configPath: String, - pushgatewayPath: String, - @volatile private var httpClientFactory: Config => HttpClient - ) extends MetricReporter { + configPath: String, + pushgatewayPath: String, + @volatile private var httpClientFactory: Config => HttpClient +) extends MetricReporter { private val _logger = LoggerFactory.getLogger(classOf[PrometheusPushgatewayReporter]) - private val _snapshotAccumulator = PeriodSnapshot.accumulator(Duration.ofDays(365 * 5), Duration.ZERO, Duration.ofDays(365 * 5)) + private val _snapshotAccumulator = + PeriodSnapshot.accumulator(Duration.ofDays(365 * 5), Duration.ZERO, Duration.ofDays(365 * 5)) @volatile private var httpClient: HttpClient = _ @volatile private var settings: PrometheusSettings.Generic = _ @@ -56,8 +57,8 @@ class PrometheusPushgatewayReporter( val message = scrapeDataBuilder.build() - httpClient.doPost("text/plain; version=0.0.4", message.toCharArray.map(_.toByte)).failed.foreach( - exception => _logger.error("Failed to send metrics to Prometheus Pushgateway", exception) + httpClient.doPost("text/plain; version=0.0.4", message.toCharArray.map(_.toByte)).failed.foreach(exception => + _logger.error("Failed to send metrics to Prometheus Pushgateway", exception) ) } diff --git a/reporters/kamon-prometheus/src/main/scala/kamon/prometheus/PrometheusReporter.scala b/reporters/kamon-prometheus/src/main/scala/kamon/prometheus/PrometheusReporter.scala index afd84ef8c..4c9024838 100644 --- a/reporters/kamon-prometheus/src/main/scala/kamon/prometheus/PrometheusReporter.scala +++ b/reporters/kamon-prometheus/src/main/scala/kamon/prometheus/PrometheusReporter.scala @@ -26,14 +26,16 @@ import kamon.prometheus.PrometheusReporter.DefaultConfigPath import kamon.prometheus.embeddedhttp.EmbeddedHttpServer import org.slf4j.LoggerFactory -class PrometheusReporter(configPath: String = DefaultConfigPath, initialConfig: Config = Kamon.config()) extends MetricReporter with ScrapeSource { +class PrometheusReporter(configPath: String = DefaultConfigPath, initialConfig: Config = Kamon.config()) + extends MetricReporter with ScrapeSource { import PrometheusReporter.Settings.readSettings import PrometheusSettings.environmentTags private val _logger = LoggerFactory.getLogger(classOf[PrometheusReporter]) private var _embeddedHttpServer: Option[EmbeddedHttpServer] = None - private val _snapshotAccumulator = PeriodSnapshot.accumulator(Duration.ofDays(365 * 5), Duration.ZERO, Duration.ofDays(365 * 5)) + private val _snapshotAccumulator = + PeriodSnapshot.accumulator(Duration.ofDays(365 * 5), Duration.ZERO, Duration.ofDays(365 * 5)) @volatile private var _preparedScrapeData: String = "# The kamon-prometheus module didn't receive any data just yet.\n" @@ -56,7 +58,6 @@ class PrometheusReporter(configPath: String = DefaultConfigPath, initialConfig: PrometheusReporter._lastCreatedInstance = None } - override def reconfigure(newConfig: Config): Unit = { _reporterSettings = readSettings(newConfig.getConfig(configPath)) _config = newConfig @@ -71,7 +72,9 @@ class PrometheusReporter(configPath: String = DefaultConfigPath, initialConfig: scrapeDataBuilder.appendCounters(currentData.counters) scrapeDataBuilder.appendGauges(currentData.gauges) - scrapeDataBuilder.appendDistributionMetricsAsGauges(snapshot.rangeSamplers ++ snapshot.histograms ++ snapshot.timers) + scrapeDataBuilder.appendDistributionMetricsAsGauges( + snapshot.rangeSamplers ++ snapshot.histograms ++ snapshot.timers + ) scrapeDataBuilder.appendHistograms(currentData.histograms) scrapeDataBuilder.appendHistograms(currentData.timers) scrapeDataBuilder.appendHistograms(currentData.rangeSamplers) @@ -84,12 +87,23 @@ class PrometheusReporter(configPath: String = DefaultConfigPath, initialConfig: private def startEmbeddedServerIfEnabled(): Unit = { if (_reporterSettings.startEmbeddedServer) { val server = _reporterSettings.createEmbeddedHttpServerClass() - .getConstructor(Array[Class[_]](classOf[String], classOf[Int], classOf[String], classOf[ScrapeSource], classOf[Config]): _*) - .newInstance(_reporterSettings.embeddedServerHostname, - _reporterSettings.embeddedServerPort:Integer, - _reporterSettings.embeddedServerPath, - this, _config) - _logger.info(s"Started the embedded HTTP server on http://${_reporterSettings.embeddedServerHostname}:${_reporterSettings.embeddedServerPort}${_reporterSettings.embeddedServerPath}") + .getConstructor(Array[Class[_]]( + classOf[String], + classOf[Int], + classOf[String], + classOf[ScrapeSource], + classOf[Config] + ): _*) + .newInstance( + _reporterSettings.embeddedServerHostname, + _reporterSettings.embeddedServerPort: Integer, + _reporterSettings.embeddedServerPath, + this, + _config + ) + _logger.info( + s"Started the embedded HTTP server on http://${_reporterSettings.embeddedServerHostname}:${_reporterSettings.embeddedServerPort}${_reporterSettings.embeddedServerPath}" + ) _embeddedHttpServer = Some(server) } } @@ -117,7 +131,6 @@ object PrometheusReporter { _lastCreatedInstance.map(_.scrapeData()) } - class Factory extends ModuleFactory { override def create(settings: ModuleFactory.Settings): Module = { val reporter = new PrometheusReporter(DefaultConfigPath, settings.config) @@ -131,17 +144,17 @@ object PrometheusReporter { } case class Settings( - startEmbeddedServer: Boolean, - embeddedServerHostname: String, - embeddedServerPort: Int, - embeddedServerPath: String, - embeddedServerImpl: String, - generic: PrometheusSettings.Generic - ) { + startEmbeddedServer: Boolean, + embeddedServerHostname: String, + embeddedServerPort: Int, + embeddedServerPath: String, + embeddedServerImpl: String, + generic: PrometheusSettings.Generic + ) { def createEmbeddedHttpServerClass(): Class[_ <: EmbeddedHttpServer] = { val clz = embeddedServerImpl match { case "sun" => "kamon.prometheus.embeddedhttp.SunEmbeddedHttpServer" - case fqcn => fqcn + case fqcn => fqcn } Class.forName(clz).asInstanceOf[Class[_ <: EmbeddedHttpServer]] } @@ -165,4 +178,3 @@ object PrometheusReporter { trait ScrapeSource { def scrapeData(): String } - diff --git a/reporters/kamon-prometheus/src/main/scala/kamon/prometheus/ScrapeDataBuilder.scala b/reporters/kamon-prometheus/src/main/scala/kamon/prometheus/ScrapeDataBuilder.scala index 5403e1385..5df3b1490 100644 --- a/reporters/kamon-prometheus/src/main/scala/kamon/prometheus/ScrapeDataBuilder.scala +++ b/reporters/kamon-prometheus/src/main/scala/kamon/prometheus/ScrapeDataBuilder.scala @@ -50,35 +50,39 @@ class ScrapeDataBuilder(prometheusConfig: PrometheusSettings.Generic, environmen } def appendDistributionMetricsAsGauges(distributions: Seq[MetricSnapshot.Distributions]): ScrapeDataBuilder = { - def gaugeFilter(metric:MetricSnapshot.Distributions):Boolean = prometheusConfig.gaugeSettings.metricMatchers.exists(_.accept(metric.name)) - def avg(snap:Instrument.Snapshot[Distribution]):Double = if(snap.value.count == 0) 0 else snap.value.sum/snap.value.count + def gaugeFilter(metric: MetricSnapshot.Distributions): Boolean = + prometheusConfig.gaugeSettings.metricMatchers.exists(_.accept(metric.name)) + def avg(snap: Instrument.Snapshot[Distribution]): Double = + if (snap.value.count == 0) 0 else snap.value.sum / snap.value.count distributions .filter(gaugeFilter) - .map{ metric => + .map { metric => val settings = Metric.Settings.ForValueInstrument(metric.settings.unit, metric.settings.autoUpdateInterval) Seq( MetricSnapshot.ofValues( - name = metric.name+".min", + name = metric.name + ".min", description = metric.description, settings = settings, - instruments = metric.instruments.map(snap => Instrument.Snapshot[Double](snap.tags, snap.value.min.toDouble)) + instruments = + metric.instruments.map(snap => Instrument.Snapshot[Double](snap.tags, snap.value.min.toDouble)) ), MetricSnapshot.ofValues( - name = metric.name+".max", + name = metric.name + ".max", description = metric.description, settings = settings, - instruments = metric.instruments.map(snap => Instrument.Snapshot[Double](snap.tags, snap.value.max.toDouble)) + instruments = + metric.instruments.map(snap => Instrument.Snapshot[Double](snap.tags, snap.value.max.toDouble)) ), MetricSnapshot.ofValues( - name = metric.name+".avg", + name = metric.name + ".avg", description = metric.description, settings = settings, instruments = metric.instruments.map(snap => Instrument.Snapshot[Double](snap.tags, avg(snap))) ) ) - }.flatten - .foreach(appendGaugeMetric) + }.flatten + .foreach(appendGaugeMetric) this } @@ -86,7 +90,7 @@ class ScrapeDataBuilder(prometheusConfig: PrometheusSettings.Generic, environmen val unit = metric.settings.unit val normalizedMetricName = normalizeCounterMetricName(metric.name, unit) - if(metric.description.nonEmpty) + if (metric.description.nonEmpty) append("# HELP ").append(normalizedMetricName).append(" ").append(metric.description).append("\n") append("# TYPE ").append(normalizedMetricName).append(" counter\n") @@ -104,7 +108,7 @@ class ScrapeDataBuilder(prometheusConfig: PrometheusSettings.Generic, environmen val unit = metric.settings.unit val normalizedMetricName = normalizeMetricName(metric.name, unit) - if(metric.description.nonEmpty) + if (metric.description.nonEmpty) append("# HELP ").append(normalizedMetricName).append(" ").append(metric.description).append("\n") append("# TYPE ").append(normalizedMetricName).append(" gauge\n") @@ -121,9 +125,9 @@ class ScrapeDataBuilder(prometheusConfig: PrometheusSettings.Generic, environmen private def appendDistributionMetric(metric: MetricSnapshot.Distributions): Unit = { val reportAsSummary = prometheusConfig.summarySettings.metricMatchers.exists(_.accept(metric.name)) if (reportAsSummary) { - appendDistributionMetricAsSummary(metric) + appendDistributionMetricAsSummary(metric) } else { - appendDistributionMetricAsHistogram(metric) + appendDistributionMetricAsHistogram(metric) } } @@ -131,15 +135,20 @@ class ScrapeDataBuilder(prometheusConfig: PrometheusSettings.Generic, environmen val unit = metric.settings.unit val normalizedMetricName = normalizeMetricName(metric.name, unit) - if(metric.description.nonEmpty) + if (metric.description.nonEmpty) append("# HELP ").append(normalizedMetricName).append(" ").append(metric.description).append("\n") append("# TYPE ").append(normalizedMetricName).append(" histogram").append("\n") metric.instruments.foreach(instrument => { - if(instrument.value.count > 0) { - appendHistogramBuckets(normalizedMetricName, instrument.tags, instrument.value, unit, - resolveBucketConfiguration(metric.name, unit)) + if (instrument.value.count > 0) { + appendHistogramBuckets( + normalizedMetricName, + instrument.tags, + instrument.value, + unit, + resolveBucketConfiguration(metric.name, unit) + ) val count = format(instrument.value.count) val sum = format(convert(instrument.value.sum, unit)) @@ -153,13 +162,13 @@ class ScrapeDataBuilder(prometheusConfig: PrometheusSettings.Generic, environmen val unit = metric.settings.unit val normalizedMetricName = normalizeMetricName(metric.name, unit) - if(metric.description.nonEmpty) + if (metric.description.nonEmpty) append("# HELP ").append(normalizedMetricName).append(" ").append(metric.description).append("\n") append("# TYPE ").append(normalizedMetricName).append(" summary").append("\n") metric.instruments.foreach(instrument => { - if(instrument.value.count > 0) { + if (instrument.value.count > 0) { appendSummaryQuantiles( normalizedMetricName, instrument.tags, @@ -187,21 +196,23 @@ class ScrapeDataBuilder(prometheusConfig: PrometheusSettings.Generic, environmen prometheusConfig.customBuckets.getOrElse( metricName, unit.dimension match { - case Time => prometheusConfig.timeBuckets - case Information => prometheusConfig.informationBuckets - case Percentage => prometheusConfig.percentageBuckets - case _ => prometheusConfig.defaultBuckets + case Time => prometheusConfig.timeBuckets + case Information => prometheusConfig.informationBuckets + case Percentage => prometheusConfig.percentageBuckets + case _ => prometheusConfig.defaultBuckets } ) - private def appendSummaryQuantiles(name: String, - tags: TagSet, - distribution: Distribution, - unit: MeasurementUnit, - quantiles: Seq[java.lang.Double]): Unit = { + private def appendSummaryQuantiles( + name: String, + tags: TagSet, + distribution: Distribution, + unit: MeasurementUnit, + quantiles: Seq[java.lang.Double] + ): Unit = { val percentileIter = distribution.percentilesIterator val percentiles = quantiles.sorted.map { quant => - //find first percentile in iterator that is grater or equal to wanted quantile and extract value right away since the percentile is mutable + // find first percentile in iterator that is grater or equal to wanted quantile and extract value right away since the percentile is mutable quant -> percentileIter.find { _.rank >= (quant * 100) }.map(_.value).getOrElse(0L) @@ -213,8 +224,13 @@ class ScrapeDataBuilder(prometheusConfig: PrometheusSettings.Generic, environmen } } - private def appendHistogramBuckets(name: String, tags: TagSet, distribution: Distribution, unit: MeasurementUnit, - buckets: Seq[java.lang.Double]): Unit = { + private def appendHistogramBuckets( + name: String, + tags: TagSet, + distribution: Distribution, + unit: MeasurementUnit, + buckets: Seq[java.lang.Double] + ): Unit = { val distributionBuckets = distribution.bucketsIterator var currentDistributionBucket = distributionBuckets.next() @@ -225,18 +241,17 @@ class ScrapeDataBuilder(prometheusConfig: PrometheusSettings.Generic, environmen buckets.foreach { configuredBucket => val bucketTags = tags.withTag("le", String.valueOf(configuredBucket)) - if(currentDistributionBucketValue <= configuredBucket) { + if (currentDistributionBucketValue <= configuredBucket) { inBucketCount += leftOver leftOver = 0 - while (distributionBuckets.hasNext && currentDistributionBucketValue <= configuredBucket ) { + while (distributionBuckets.hasNext && currentDistributionBucketValue <= configuredBucket) { currentDistributionBucket = distributionBuckets.next() currentDistributionBucketValue = convert(currentDistributionBucket.value, unit) if (currentDistributionBucketValue <= configuredBucket) { inBucketCount += currentDistributionBucket.frequency - } - else + } else leftOver = currentDistributionBucket.frequency } } @@ -244,7 +259,7 @@ class ScrapeDataBuilder(prometheusConfig: PrometheusSettings.Generic, environmen appendTimeSerieValue(name, bucketTags, format(inBucketCount), "_bucket") } - while(distributionBuckets.hasNext) { + while (distributionBuckets.hasNext) { leftOver += distributionBuckets.next().frequency } @@ -262,14 +277,14 @@ class ScrapeDataBuilder(prometheusConfig: PrometheusSettings.Generic, environmen private def appendTagsTo(tags: TagSet, buffer: StringBuilder): Unit = { val allTags = tags.withTags(environmentTags) - if(allTags.nonEmpty) buffer.append("{") + if (allTags.nonEmpty) buffer.append("{") - val tagIterator = allTags.iterator(v => if(v == null) "" else v.toString) + val tagIterator = allTags.iterator(v => if (v == null) "" else v.toString) var tagCount = 0 - while(tagIterator.hasNext) { + while (tagIterator.hasNext) { val pair = tagIterator.next() - if(tagCount > 0) + if (tagCount > 0) buffer.append(",") buffer @@ -281,25 +296,25 @@ class ScrapeDataBuilder(prometheusConfig: PrometheusSettings.Generic, environmen tagCount += 1 } - if(allTags.nonEmpty) buffer.append("}") + if (allTags.nonEmpty) buffer.append("}") } private def normalizeCounterMetricName(metricName: String, unit: MeasurementUnit): String = { val normalizedMetricName = metricName.map(validNameChar(_)) - unit.dimension match { - case Time => addPostfixOnlyIfMissing(normalizedMetricName, "_seconds_total") - case Information => addPostfixOnlyIfMissing(normalizedMetricName, "_bytes_total") - case _ => addPostfixOnlyIfMissing(normalizedMetricName, "_total") + unit.dimension match { + case Time => addPostfixOnlyIfMissing(normalizedMetricName, "_seconds_total") + case Information => addPostfixOnlyIfMissing(normalizedMetricName, "_bytes_total") + case _ => addPostfixOnlyIfMissing(normalizedMetricName, "_total") } } private def normalizeMetricName(metricName: String, unit: MeasurementUnit): String = { val normalizedMetricName = metricName.map(validNameChar(_)) - unit.dimension match { - case Time => addPostfixOnlyIfMissing(normalizedMetricName, "_seconds") - case Information => addPostfixOnlyIfMissing(normalizedMetricName, "_bytes") - case _ => normalizedMetricName + unit.dimension match { + case Time => addPostfixOnlyIfMissing(normalizedMetricName, "_seconds") + case Information => addPostfixOnlyIfMissing(normalizedMetricName, "_bytes") + case _ => normalizedMetricName } } private def addPostfixOnlyIfMissing(metricName: String, postfix: String) = @@ -310,23 +325,23 @@ class ScrapeDataBuilder(prometheusConfig: PrometheusSettings.Generic, environmen label.map(validLabelChar) private def validLabelChar(char: Char): Char = - if(char.isLetterOrDigit || char == '_') char else '_' + if (char.isLetterOrDigit || char == '_') char else '_' private def validNameChar(char: Char): Char = - if(char.isLetterOrDigit || char == '_' || char == ':') char else '_' + if (char.isLetterOrDigit || char == '_' || char == ':') char else '_' private def normalizeLabelValue(value: String): String = { - if(value.contains("\\")) value.replace("\\", "\\\\") else value + if (value.contains("\\")) value.replace("\\", "\\\\") else value } private def format(value: Double): String = _numberFormat.format(value) private def convert(value: Double, unit: MeasurementUnit): Double = unit.dimension match { - case Time if unit.magnitude != time.seconds.magnitude => MeasurementUnit.convert(value, unit, time.seconds) - case Information if unit.magnitude != information.bytes.magnitude => MeasurementUnit.convert(value, unit, information.bytes) + case Time if unit.magnitude != time.seconds.magnitude => MeasurementUnit.convert(value, unit, time.seconds) + case Information if unit.magnitude != information.bytes.magnitude => + MeasurementUnit.convert(value, unit, information.bytes) case _ => value } - } diff --git a/reporters/kamon-prometheus/src/main/scala/kamon/prometheus/embeddedhttp/SunEmbeddedHttpServer.scala b/reporters/kamon-prometheus/src/main/scala/kamon/prometheus/embeddedhttp/SunEmbeddedHttpServer.scala index b4f0d036f..57175fd31 100644 --- a/reporters/kamon-prometheus/src/main/scala/kamon/prometheus/embeddedhttp/SunEmbeddedHttpServer.scala +++ b/reporters/kamon-prometheus/src/main/scala/kamon/prometheus/embeddedhttp/SunEmbeddedHttpServer.scala @@ -29,7 +29,8 @@ import java.util.zip.GZIPOutputStream import scala.collection.JavaConverters._ import scala.collection.mutable -class SunEmbeddedHttpServer(hostname: String, port: Int, path: String, scrapeSource: ScrapeSource, config: Config) extends EmbeddedHttpServer(hostname, port, scrapeSource, config) { +class SunEmbeddedHttpServer(hostname: String, port: Int, path: String, scrapeSource: ScrapeSource, config: Config) + extends EmbeddedHttpServer(hostname, port, scrapeSource, config) { private val server = { val s = HttpServer.create(new InetSocketAddress(InetAddress.getByName(hostname), port), 0) s.setExecutor(null) diff --git a/reporters/kamon-prometheus/src/test/scala/kamon/prometheus/EmbeddedHttpServerSpec.scala b/reporters/kamon-prometheus/src/test/scala/kamon/prometheus/EmbeddedHttpServerSpec.scala index 0914032c7..5338d2753 100644 --- a/reporters/kamon-prometheus/src/test/scala/kamon/prometheus/EmbeddedHttpServerSpec.scala +++ b/reporters/kamon-prometheus/src/test/scala/kamon/prometheus/EmbeddedHttpServerSpec.scala @@ -15,10 +15,10 @@ class SunHttpServerSpecSuite extends EmbeddedHttpServerSpecSuite { } abstract class EmbeddedHttpServerSpecSuite extends AnyWordSpec - with Matchers - with BeforeAndAfterAll - with KamonTestSnapshotSupport - with Eventually { + with Matchers + with BeforeAndAfterAll + with KamonTestSnapshotSupport + with Eventually { protected def testConfig: Config protected def port: Int = 9095 @@ -31,47 +31,47 @@ abstract class EmbeddedHttpServerSpecSuite extends AnyWordSpec "the embedded sun http server" should { "provide no data comment on GET to /metrics when no data loaded yet" in { - //act + // act val metrics = httpGetMetrics("/metrics") - //assert + // assert metrics shouldBe "# The kamon-prometheus module didn't receive any data just yet.\n" } "provide the metrics on GET to /metrics with empty data" in { - //arrange + // arrange testee.reportPeriodSnapshot(emptyPeriodSnapshot) - //act + // act val metrics = httpGetMetrics("/metrics") - //assert + // assert metrics shouldBe "" } "provide the metrics on GET to /metrics with data" in { - //arrange + // arrange testee.reportPeriodSnapshot(counter("jvm.mem")) - //act + // act val metrics = httpGetMetrics("/metrics") - //assert + // assert metrics shouldBe "# TYPE jvm_mem_total counter\njvm_mem_total 1.0\n" } "provide the metrics on GET to /metrics with data after reconfigure" in { - //arrange + // arrange testee.reconfigure(testConfig) testee.reportPeriodSnapshot(counter("jvm.mem")) - //act + // act val metrics = httpGetMetrics("/metrics") - //assert + // assert metrics shouldBe "# TYPE jvm_mem_total counter\njvm_mem_total 2.0\n" } "respect gzip Content-Encoding headers" in { - //arrange + // arrange testee.reportPeriodSnapshot(counter("jvm.mem")) - //act + // act val metrics = httpGetMetrics("/metrics") val gzippedMetrics = httpGetGzippedMetrics("/metrics") - //assert + // assert metrics.length should be > gzippedMetrics.length } @@ -110,6 +110,7 @@ abstract class EmbeddedHttpServerSpecSuite extends AnyWordSpec private def changeEndpoint(path: String): Config = { ConfigFactory.parseString( - s"""kamon.prometheus.embedded-server.metrics-path = ${path}""").withFallback(testConfig) + s"""kamon.prometheus.embedded-server.metrics-path = ${path}""" + ).withFallback(testConfig) } } diff --git a/reporters/kamon-prometheus/src/test/scala/kamon/prometheus/KamonTestSnapshotSupport.scala b/reporters/kamon-prometheus/src/test/scala/kamon/prometheus/KamonTestSnapshotSupport.scala index ae3a8f5ff..7c4d96a02 100644 --- a/reporters/kamon-prometheus/src/test/scala/kamon/prometheus/KamonTestSnapshotSupport.scala +++ b/reporters/kamon-prometheus/src/test/scala/kamon/prometheus/KamonTestSnapshotSupport.scala @@ -6,14 +6,21 @@ import kamon.tag.TagSet import kamon.testkit.MetricSnapshotBuilder trait KamonTestSnapshotSupport { - val emptyPeriodSnapshot: PeriodSnapshot = PeriodSnapshot(Kamon.clock().instant(), Kamon.clock().instant(), - Seq.empty, Seq.empty, Seq.empty, Seq.empty, Seq.empty) + val emptyPeriodSnapshot: PeriodSnapshot = PeriodSnapshot( + Kamon.clock().instant(), + Kamon.clock().instant(), + Seq.empty, + Seq.empty, + Seq.empty, + Seq.empty, + Seq.empty + ) def counter(metricName: String, tags: Map[String, String] = Map.empty): PeriodSnapshot = emptyPeriodSnapshot.copy(counters = Seq(MetricSnapshotBuilder.counter(metricName, TagSet.from(tags), 1L))) def gauge(metricName: String, tags: Map[String, String] = Map.empty): PeriodSnapshot = - emptyPeriodSnapshot.copy(gauges = Seq(MetricSnapshotBuilder.gauge(metricName, TagSet.from(tags), 1D))) + emptyPeriodSnapshot.copy(gauges = Seq(MetricSnapshotBuilder.gauge(metricName, TagSet.from(tags), 1d))) def histogram(metricName: String, tags: Map[String, String] = Map.empty): PeriodSnapshot = emptyPeriodSnapshot.copy(histograms = Seq(MetricSnapshotBuilder.histogram(metricName, TagSet.from(tags))(1))) @@ -23,4 +30,4 @@ trait KamonTestSnapshotSupport { def timers(metricName: String, tags: Map[String, String] = Map.empty): PeriodSnapshot = emptyPeriodSnapshot.copy(rangeSamplers = Seq(MetricSnapshotBuilder.histogram(metricName, TagSet.from(tags))(1))) -} \ No newline at end of file +} diff --git a/reporters/kamon-prometheus/src/test/scala/kamon/prometheus/MetricOverrideReporterSpec.scala b/reporters/kamon-prometheus/src/test/scala/kamon/prometheus/MetricOverrideReporterSpec.scala index df8b5997b..a6bef2636 100644 --- a/reporters/kamon-prometheus/src/test/scala/kamon/prometheus/MetricOverrideReporterSpec.scala +++ b/reporters/kamon-prometheus/src/test/scala/kamon/prometheus/MetricOverrideReporterSpec.scala @@ -23,7 +23,8 @@ import kamon.testkit.{InstrumentInspection, MetricInspection} import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec -class MetricOverrideReporterSpec extends AnyWordSpec with Matchers with MetricInspection.Syntax with InstrumentInspection.Syntax with KamonTestSnapshotSupport { +class MetricOverrideReporterSpec extends AnyWordSpec with Matchers with MetricInspection.Syntax + with InstrumentInspection.Syntax with KamonTestSnapshotSupport { "A MetricOverrideReporter" should { "apply metric overrides" in { @@ -82,11 +83,17 @@ class MetricOverrideReporterSpec extends AnyWordSpec with Matchers with MetricIn "not delete tags with the same name from other metrics" in { report(histogram("other-metric-name", Map("unwanted-tag" -> "foo", "keep-me" -> "bar"))) { snapshot => - snapshot.histograms.head.instruments.head.tags shouldBe TagSet.of("unwanted-tag", "foo").withTag("keep-me", "bar") + snapshot.histograms.head.instruments.head.tags shouldBe TagSet.of("unwanted-tag", "foo").withTag( + "keep-me", + "bar" + ) } report(rangeSampler("other-metric-name", Map("unwanted-tag" -> "foo", "keep-me" -> "bar"))) { snapshot => - snapshot.rangeSamplers.head.instruments.head.tags shouldBe TagSet.of("unwanted-tag", "foo").withTag("keep-me", "bar") + snapshot.rangeSamplers.head.instruments.head.tags shouldBe TagSet.of("unwanted-tag", "foo").withTag( + "keep-me", + "bar" + ) } report(gauge("other-metric-name", Map("unwanted-tag" -> "foo", "keep-me" -> "bar"))) { snapshot => @@ -104,7 +111,10 @@ class MetricOverrideReporterSpec extends AnyWordSpec with Matchers with MetricIn } report(rangeSampler("some-other-metric", Map("old-name" -> "foo", "leave-me" -> "bar"))) { snapshot => - snapshot.rangeSamplers.head.instruments.head.tags shouldBe TagSet.of("new-name", "foo").withTag("leave-me", "bar") + snapshot.rangeSamplers.head.instruments.head.tags shouldBe TagSet.of("new-name", "foo").withTag( + "leave-me", + "bar" + ) } report(gauge("some-other-metric", Map("old-name" -> "foo", "leave-me" -> "bar"))) { snapshot => @@ -152,7 +162,8 @@ class MetricOverrideReporterSpec extends AnyWordSpec with Matchers with MetricIn | } | } |} - """.stripMargin) + """.stripMargin + ) val reporter = new DummyMetricReporter val wrapper = new MetricOverrideReporter(reporter, config) @@ -173,5 +184,4 @@ class MetricOverrideReporterSpec extends AnyWordSpec with Matchers with MetricIn assertions(reporter.latestSnapshot) } - } diff --git a/reporters/kamon-prometheus/src/test/scala/kamon/prometheus/ScrapeDataBuilderSpec.scala b/reporters/kamon-prometheus/src/test/scala/kamon/prometheus/ScrapeDataBuilderSpec.scala index b937859a5..c3dbdf943 100644 --- a/reporters/kamon-prometheus/src/test/scala/kamon/prometheus/ScrapeDataBuilderSpec.scala +++ b/reporters/kamon-prometheus/src/test/scala/kamon/prometheus/ScrapeDataBuilderSpec.scala @@ -21,7 +21,7 @@ class ScrapeDataBuilderSpec extends AnyWordSpec with Matchers { .appendCounters(Seq(counterOne)) .appendGauges(Seq(gaugeOne)) .build() should include { - """ + """ |# TYPE counter_one_seconds_total counter |counter_one_seconds_total 10.0 |# TYPE gauge_one_seconds gauge @@ -35,9 +35,9 @@ class ScrapeDataBuilderSpec extends AnyWordSpec with Matchers { val gaugeOne = MetricSnapshotBuilder.gauge("gauge-one", "", TagSet.Empty, information.bytes, 20) builder() - .appendCounters(Seq(counterOne)) - .appendGauges(Seq(gaugeOne)) - .build() should include { + .appendCounters(Seq(counterOne)) + .appendGauges(Seq(gaugeOne)) + .build() should include { """ |# TYPE counter_one_bytes_total counter |counter_one_bytes_total 10.0 @@ -48,13 +48,15 @@ class ScrapeDataBuilderSpec extends AnyWordSpec with Matchers { } "normalize tag names" in { - val counterOne = MetricSnapshotBuilder.counter("app:counter-one", "", TagSet.of("tag.with.dots", "value"), time.seconds, 10) - val gaugeOne = MetricSnapshotBuilder.gauge("gauge-one", "", TagSet.of("tag-with-dashes", "value"), time.seconds, 20) + val counterOne = + MetricSnapshotBuilder.counter("app:counter-one", "", TagSet.of("tag.with.dots", "value"), time.seconds, 10) + val gaugeOne = + MetricSnapshotBuilder.gauge("gauge-one", "", TagSet.of("tag-with-dashes", "value"), time.seconds, 20) builder() - .appendCounters(Seq(counterOne)) - .appendGauges(Seq(gaugeOne)) - .build() should include { + .appendCounters(Seq(counterOne)) + .appendGauges(Seq(gaugeOne)) + .build() should include { """ |# TYPE app:counter_one_seconds_total counter |app:counter_one_seconds_total{tag_with_dots="value"} 10.0 @@ -65,7 +67,13 @@ class ScrapeDataBuilderSpec extends AnyWordSpec with Matchers { } "escape backslash in tag values" in { - val counter = MetricSnapshotBuilder.counter("counter.with.backslash", "", TagSet.of("path", "c:\\users\\temp"), time.seconds, 10) + val counter = MetricSnapshotBuilder.counter( + "counter.with.backslash", + "", + TagSet.of("path", "c:\\users\\temp"), + time.seconds, + 10 + ) builder() .appendCounters(Seq(counter)) @@ -78,10 +86,16 @@ class ScrapeDataBuilderSpec extends AnyWordSpec with Matchers { } } - "not add extra '_total' postfix if metric name already ends with it when using units" in { - val counterOne = MetricSnapshotBuilder.counter("app:counter-one-seconds-total", "", TagSet.of("tag.with.dots", "value"), time.seconds, 10) - val gaugeOne = MetricSnapshotBuilder.gauge("gauge-one-seconds", "", TagSet.of("tag-with-dashes", "value"), time.seconds, 20) + val counterOne = MetricSnapshotBuilder.counter( + "app:counter-one-seconds-total", + "", + TagSet.of("tag.with.dots", "value"), + time.seconds, + 10 + ) + val gaugeOne = + MetricSnapshotBuilder.gauge("gauge-one-seconds", "", TagSet.of("tag-with-dashes", "value"), time.seconds, 20) builder() .appendCounters(Seq(counterOne)) @@ -96,7 +110,8 @@ class ScrapeDataBuilderSpec extends AnyWordSpec with Matchers { } } "not add extra '_total' postfix if metric name already ends with it when not using units" in { - val counterOne = MetricSnapshotBuilder.counter("app:counter-one-total", "", TagSet.of("tag.with.dots", "value"), 10) + val counterOne = + MetricSnapshotBuilder.counter("app:counter-one-total", "", TagSet.of("tag.with.dots", "value"), 10) val gaugeOne = MetricSnapshotBuilder.gauge("gauge-one", "", TagSet.of("tag-with-dashes", "value"), 20) builder() @@ -155,9 +170,9 @@ class ScrapeDataBuilderSpec extends AnyWordSpec with Matchers { """.stripMargin ).withFallback(ConfigFactory.defaultReference()).getConfig("kamon.prometheus")) - config.customBuckets should contain allOf( - ("singleword" -> Seq(1D, 2D, 3D)), - ("with.several.dots" -> Seq(3D, 2D, 1D)) + config.customBuckets should contain allOf ( + ("singleword" -> Seq(1d, 2d, 3d)), + ("with.several.dots" -> Seq(3d, 2d, 1d)) ) } @@ -165,7 +180,9 @@ class ScrapeDataBuilderSpec extends AnyWordSpec with Matchers { "override histogram buckets with custom configuration" in { val customBucketsHistogram = constantDistribution("histogram.custom-buckets", none, 1, 10) - builder(customBuckets = Map("histogram.custom-buckets" -> Seq(1D, 2D, 4D))).appendHistograms(Seq(customBucketsHistogram)).build() should include { + builder(customBuckets = Map("histogram.custom-buckets" -> Seq(1d, 2d, 4d))).appendHistograms(Seq( + customBucketsHistogram + )).build() should include { """ |# TYPE histogram_custom_buckets histogram |histogram_custom_buckets_bucket{le="1.0"} 1.0 @@ -184,7 +201,7 @@ class ScrapeDataBuilderSpec extends AnyWordSpec with Matchers { val histogramThree = constantDistribution("histogram-three", none, 5, 10) val histogramWithZero = constantDistribution("histogram-with-zero", none, 0, 10) - builder(buckets = Seq(15D)).appendHistograms(Seq(histogramOne)).build() should include { + builder(buckets = Seq(15d)).appendHistograms(Seq(histogramOne)).build() should include { """ |# TYPE histogram_one histogram |histogram_one_bucket{le="15.0"} 10.0 @@ -194,7 +211,7 @@ class ScrapeDataBuilderSpec extends AnyWordSpec with Matchers { """.stripMargin.trim() } - builder(buckets = Seq(5D, 10D, 15D, 20D)).appendHistograms(Seq(histogramTwo)).build() should include { + builder(buckets = Seq(5d, 10d, 15d, 20d)).appendHistograms(Seq(histogramTwo)).build() should include { """ |# TYPE histogram_two histogram |histogram_two_bucket{le="5.0"} 5.0 @@ -207,7 +224,7 @@ class ScrapeDataBuilderSpec extends AnyWordSpec with Matchers { """.stripMargin.trim() } - builder(buckets = Seq(3D)).appendHistograms(Seq(histogramThree)).build() should include { + builder(buckets = Seq(3d)).appendHistograms(Seq(histogramThree)).build() should include { """ |# TYPE histogram_three histogram |histogram_three_bucket{le="3.0"} 0.0 @@ -217,7 +234,7 @@ class ScrapeDataBuilderSpec extends AnyWordSpec with Matchers { """.stripMargin.trim() } - builder(buckets = Seq(3D, 50D)).appendHistograms(Seq(histogramThree)).build() should include { + builder(buckets = Seq(3d, 50d)).appendHistograms(Seq(histogramThree)).build() should include { """ |# TYPE histogram_three histogram |histogram_three_bucket{le="3.0"} 0.0 @@ -228,7 +245,7 @@ class ScrapeDataBuilderSpec extends AnyWordSpec with Matchers { """.stripMargin.trim() } - builder(buckets = Seq(3D, 50D, 60D, 70D)).appendHistograms(Seq(histogramThree)).build() should include { + builder(buckets = Seq(3d, 50d, 60d, 70d)).appendHistograms(Seq(histogramThree)).build() should include { """ |# TYPE histogram_three histogram |histogram_three_bucket{le="3.0"} 0.0 @@ -241,7 +258,7 @@ class ScrapeDataBuilderSpec extends AnyWordSpec with Matchers { """.stripMargin.trim() } - builder(buckets = Seq(7D)).appendHistograms(Seq(histogramThree)).build() should include { + builder(buckets = Seq(7d)).appendHistograms(Seq(histogramThree)).build() should include { """ |# TYPE histogram_three histogram |histogram_three_bucket{le="7.0"} 3.0 @@ -251,7 +268,9 @@ class ScrapeDataBuilderSpec extends AnyWordSpec with Matchers { """.stripMargin.trim() } - builder(buckets = Seq(0.005D, 0.05D, 0.5D, 1D, 2D, 2.1D, 2.2D, 2.3D, 10D)).appendHistograms(Seq(histogramWithZero)).build() should include { + builder(buckets = Seq(0.005d, 0.05d, 0.5d, 1d, 2d, 2.1d, 2.2d, 2.3d, 10d)).appendHistograms( + Seq(histogramWithZero) + ).build() should include { """ |# TYPE histogram_with_zero histogram |histogram_with_zero_bucket{le="0.005"} 1.0 @@ -375,13 +394,14 @@ class ScrapeDataBuilderSpec extends AnyWordSpec with Matchers { } "include global custom tags from the Kamon.environment.tags" in { - val counterOne = MetricSnapshotBuilder.counter("counter-one", "", TagSet.of("tag.with.dots", "value"), time.seconds, 10) + val counterOne = + MetricSnapshotBuilder.counter("counter-one", "", TagSet.of("tag.with.dots", "value"), time.seconds, 10) val gaugeOne = MetricSnapshotBuilder.gauge("gauge-one", "", TagSet.Empty, time.seconds, 20) builder(environmentTags = TagSet.of("env_key", "env_value")) - .appendCounters(Seq(counterOne)) - .appendGauges(Seq(gaugeOne)) - .build() should include { + .appendCounters(Seq(counterOne)) + .appendGauges(Seq(gaugeOne)) + .build() should include { """ |# TYPE counter_one_seconds_total counter |counter_one_seconds_total{tag_with_dots="value",env_key="env_value"} 10.0 @@ -392,8 +412,10 @@ class ScrapeDataBuilderSpec extends AnyWordSpec with Matchers { } "let environment tags have precedence over custom tags" in { - val counter = MetricSnapshotBuilder.counter("some-metric", "", TagSet.of("custom.tag", "custom-value"), time.seconds, 10) - val gauge = MetricSnapshotBuilder.gauge("some-metric", "", TagSet.of("custom.tag", "custom-value"), time.seconds, 10D) + val counter = + MetricSnapshotBuilder.counter("some-metric", "", TagSet.of("custom.tag", "custom-value"), time.seconds, 10) + val gauge = + MetricSnapshotBuilder.gauge("some-metric", "", TagSet.of("custom.tag", "custom-value"), time.seconds, 10d) builder(environmentTags = TagSet.of("custom.tag", "environment-value")) .appendCounters(Seq(counter)) @@ -409,11 +431,13 @@ class ScrapeDataBuilderSpec extends AnyWordSpec with Matchers { } } - private def builder(buckets: Seq[java.lang.Double] = Seq(5D, 7D, 8D, 9D, 10D, 11D, 12D), - customBuckets: Map[String, Seq[java.lang.Double]] = Map("histogram.custom-buckets" -> Seq(1D, 3D)), - environmentTags: TagSet = TagSet.Empty, - withSummary: Seq[String] = Seq.empty, - withGauges: Seq[String] = Seq.empty) = { + private def builder( + buckets: Seq[java.lang.Double] = Seq(5d, 7d, 8d, 9d, 10d, 11d, 12d), + customBuckets: Map[String, Seq[java.lang.Double]] = Map("histogram.custom-buckets" -> Seq(1d, 3d)), + environmentTags: TagSet = TagSet.Empty, + withSummary: Seq[String] = Seq.empty, + withGauges: Seq[String] = Seq.empty + ) = { new ScrapeDataBuilder( PrometheusSettings.Generic( buckets, @@ -423,11 +447,17 @@ class ScrapeDataBuilderSpec extends AnyWordSpec with Matchers { customBuckets, false, SummarySettings(Seq(0.5, 0.75, 0.95, 0.99), withSummary.map(Glob)), - GaugeSettings(withGauges.map(Glob))), + GaugeSettings(withGauges.map(Glob)) + ), environmentTags ) } - private def constantDistribution(name: String, unit: MeasurementUnit, lower: Long, upper: Long): MetricSnapshot.Distributions = + private def constantDistribution( + name: String, + unit: MeasurementUnit, + lower: Long, + upper: Long + ): MetricSnapshot.Distributions = MetricSnapshotBuilder.histogram(name, "", TagSet.Empty)((lower to upper): _*) } diff --git a/reporters/kamon-statsd/src/main/scala/kamon/statsd/SimpleMetricKeyGenerator.scala b/reporters/kamon-statsd/src/main/scala/kamon/statsd/SimpleMetricKeyGenerator.scala index f306b4496..c7149d89b 100644 --- a/reporters/kamon-statsd/src/main/scala/kamon/statsd/SimpleMetricKeyGenerator.scala +++ b/reporters/kamon-statsd/src/main/scala/kamon/statsd/SimpleMetricKeyGenerator.scala @@ -42,11 +42,12 @@ class SimpleMetricKeyGenerator(statsDConfig: Config) extends MetricKeyGenerator private def createNormalizer(strategy: String): Normalizer = strategy match { case "percent-encode" => PercentEncoder.encode - case "normalize" => (s: String) => s.replace(": ", "-").replace(":", "-").replace(" ", "_").replace("/", "_").replace(".", "_") + case "normalize" => + (s: String) => s.replace(": ", "-").replace(":", "-").replace(" ", "_").replace("/", "_").replace(".", "_") } def generateKey(name: String, metricTags: TagSet): String = { - val tags = if(includeEnvironmentTags) metricTags.withTags(environmentTags) else metricTags + val tags = if (includeEnvironmentTags) metricTags.withTags(environmentTags) else metricTags val stringTags = if (tags.nonEmpty) "." + sortAndConcatenateTags(tags) else "" s"$baseName.${normalizer(name)}$stringTags" } diff --git a/reporters/kamon-statsd/src/main/scala/kamon/statsd/StatsDReporter.scala b/reporters/kamon-statsd/src/main/scala/kamon/statsd/StatsDReporter.scala index 14f11667a..298b8b398 100644 --- a/reporters/kamon-statsd/src/main/scala/kamon/statsd/StatsDReporter.scala +++ b/reporters/kamon-statsd/src/main/scala/kamon/statsd/StatsDReporter.scala @@ -33,13 +33,15 @@ import org.slf4j.LoggerFactory class StatsDReporter(configPath: String) extends MetricReporter { private val logger = LoggerFactory.getLogger(classOf[StatsDReporter]) - @volatile private var reporterConfiguration = StatsDReporter.Settings.readSettings(Kamon.config().getConfig(configPath)) + @volatile private var reporterConfiguration = + StatsDReporter.Settings.readSettings(Kamon.config().getConfig(configPath)) val symbols: DecimalFormatSymbols = DecimalFormatSymbols.getInstance(Locale.US) symbols.setDecimalSeparator('.') // Just in case there is some weird locale config we are not aware of. // Absurdly high number of decimal digits, let the other end loose precision if it needs to. - val samplingRateFormat = new DecimalFormat("#.################################################################", symbols) + val samplingRateFormat = + new DecimalFormat("#.################################################################", symbols) val clientChannel: DatagramChannel = DatagramChannel.open() logger.info("Started the Kamon StatsD reporter") @@ -63,11 +65,11 @@ class StatsDReporter(configPath: String) extends MetricReporter { ) for { - counter <- snapshot.counters - instrument <- counter.instruments + counter <- snapshot.counters + instrument <- counter.instruments } { - if(instrument.value != 0 || reporterConfiguration.sendZeroValues) + if (instrument.value != 0 || reporterConfiguration.sendZeroValues) packetBuffer.appendMeasurement( key = keyGenerator.generateKey(counter.name, instrument.tags), measurementData = encodeStatsDCounter(reporterConfiguration, instrument.value, counter.settings.unit) @@ -75,23 +77,24 @@ class StatsDReporter(configPath: String) extends MetricReporter { } for { - gauge <- snapshot.gauges - instrument <- gauge.instruments + gauge <- snapshot.gauges + instrument <- gauge.instruments } { - if(instrument.value != 0D || reporterConfiguration.sendZeroValues) { + if (instrument.value != 0d || reporterConfiguration.sendZeroValues) { packetBuffer.appendMeasurement( key = keyGenerator.generateKey(gauge.name, instrument.tags), - measurementData = encodeStatsDGauge(reporterConfiguration, instrument.value, gauge.settings.unit)) + measurementData = encodeStatsDGauge(reporterConfiguration, instrument.value, gauge.settings.unit) + ) } } for { - metric <- snapshot.histograms ++ snapshot.rangeSamplers ++ snapshot.timers - instrument <- metric.instruments - bucket <- instrument.value.bucketsIterator + metric <- snapshot.histograms ++ snapshot.rangeSamplers ++ snapshot.timers + instrument <- metric.instruments + bucket <- instrument.value.bucketsIterator } { - if(bucket.value != 0 || reporterConfiguration.sendZeroValues) { + if (bucket.value != 0 || reporterConfiguration.sendZeroValues) { val bucketData = encodeStatsDTimer(reporterConfiguration, bucket.value, bucket.frequency, metric.settings.unit) packetBuffer.appendMeasurement(keyGenerator.generateKey(metric.name, instrument.tags), bucketData) } @@ -106,17 +109,24 @@ class StatsDReporter(configPath: String) extends MetricReporter { private def encodeStatsDGauge(config: StatsDReporter.Settings, value: Double, unit: MeasurementUnit): String = s"${scale(config, value.toLong, unit)}|g" - private def encodeStatsDTimer(config: StatsDReporter.Settings, level: Long, count: Long, unit: MeasurementUnit): String = { - val samplingRate: Double = 1D / count - val sampled = if (samplingRate != 1D) "|@" + samplingRateFormat.format(samplingRate) else "" + private def encodeStatsDTimer( + config: StatsDReporter.Settings, + level: Long, + count: Long, + unit: MeasurementUnit + ): String = { + val samplingRate: Double = 1d / count + val sampled = if (samplingRate != 1d) "|@" + samplingRateFormat.format(samplingRate) else "" s"${scale(config, level, unit)}|ms$sampled" } - private[statsd] def scale(config: StatsDReporter.Settings, value: Long, unit: MeasurementUnit): Double = unit.dimension match { - case Time if unit.magnitude != config.timeUnit.magnitude => MeasurementUnit.convert(value, unit, config.timeUnit) - case Information if unit.magnitude != config.informationUnit.magnitude => MeasurementUnit.convert(value, unit, config.informationUnit) - case _ => value - } + private[statsd] def scale(config: StatsDReporter.Settings, value: Long, unit: MeasurementUnit): Double = + unit.dimension match { + case Time if unit.magnitude != config.timeUnit.magnitude => MeasurementUnit.convert(value, unit, config.timeUnit) + case Information if unit.magnitude != config.informationUnit.magnitude => + MeasurementUnit.convert(value, unit, config.informationUnit) + case _ => value + } } object StatsDReporter { @@ -139,7 +149,8 @@ object StatsDReporter { object Settings { def readSettings(reporterConfiguration: Config): StatsDReporter.Settings = { StatsDReporter.Settings( - agentAddress = new InetSocketAddress(reporterConfiguration.getString("hostname"), reporterConfiguration.getInt("port")), + agentAddress = + new InetSocketAddress(reporterConfiguration.getString("hostname"), reporterConfiguration.getInt("port")), maxPacketSize = reporterConfiguration.getBytes("max-packet-size"), timeUnit = readTimeUnit(reporterConfiguration.getString("time-unit")), informationUnit = readInformationUnit(reporterConfiguration.getString("information-unit")), @@ -150,12 +161,19 @@ object StatsDReporter { } private def loadKeyGenerator(keyGeneratorFQCN: String, config: Config): MetricKeyGenerator = { - new DynamicAccess(getClass.getClassLoader).createInstanceFor[MetricKeyGenerator](keyGeneratorFQCN, (classOf[Config], config) :: Nil) + new DynamicAccess(getClass.getClassLoader).createInstanceFor[MetricKeyGenerator]( + keyGeneratorFQCN, + (classOf[Config], config) :: Nil + ) } } - private[statsd] class MetricDataPacketBuffer(maxPacketSizeInBytes: Long, maxPacketsPerMilli: Int, - channel: DatagramChannel, remote: InetSocketAddress) { + private[statsd] class MetricDataPacketBuffer( + maxPacketSizeInBytes: Long, + maxPacketsPerMilli: Int, + channel: DatagramChannel, + remote: InetSocketAddress + ) { val rateLimiter = new FlushRateLimiter(maxPacketsPerMilli) val metricSeparator = "\n" @@ -212,8 +230,8 @@ object StatsDReporter { def waitIfNecessary(): Unit = { val current = currentMilli() - if(current == lastMilli) { - if(countAtLastMilli < maxPacketsPerMilli) + if (current == lastMilli) { + if (countAtLastMilli < maxPacketsPerMilli) countAtLastMilli += 1 else { Thread.sleep(1) diff --git a/reporters/kamon-statsd/src/main/scala/kamon/statsd/package.scala b/reporters/kamon-statsd/src/main/scala/kamon/statsd/package.scala index 6493cf0bd..07e619bea 100644 --- a/reporters/kamon-statsd/src/main/scala/kamon/statsd/package.scala +++ b/reporters/kamon-statsd/src/main/scala/kamon/statsd/package.scala @@ -21,20 +21,18 @@ import kamon.metric.MeasurementUnit.{information, time} package object statsd { def readTimeUnit(unit: String): MeasurementUnit = unit match { - case "s" => time.seconds - case "ms" => time.milliseconds - case "µs" => time.microseconds - case "ns" => time.nanoseconds - case other => sys.error(s"Invalid time unit setting [$other], the possible values are [s, ms, µs, ns]") + case "s" => time.seconds + case "ms" => time.milliseconds + case "µs" => time.microseconds + case "ns" => time.nanoseconds + case other => sys.error(s"Invalid time unit setting [$other], the possible values are [s, ms, µs, ns]") } def readInformationUnit(unit: String): MeasurementUnit = unit match { - case "b" => information.bytes - case "kb" => information.kilobytes - case "mb" => information.megabytes - case "gb" => information.gigabytes - case other => sys.error(s"Invalid information unit setting [$other], the possible values are [b, kb, mb, gb]") + case "b" => information.bytes + case "kb" => information.kilobytes + case "mb" => information.megabytes + case "gb" => information.gigabytes + case other => sys.error(s"Invalid information unit setting [$other], the possible values are [b, kb, mb, gb]") } } - - diff --git a/reporters/kamon-statsd/src/test/scala/kamon/statsd/MetricDataPacketBufferSpec.scala b/reporters/kamon-statsd/src/test/scala/kamon/statsd/MetricDataPacketBufferSpec.scala index f2326a455..e2f5717cd 100644 --- a/reporters/kamon-statsd/src/test/scala/kamon/statsd/MetricDataPacketBufferSpec.scala +++ b/reporters/kamon-statsd/src/test/scala/kamon/statsd/MetricDataPacketBufferSpec.scala @@ -16,7 +16,6 @@ class MetricDataPacketBufferSpec extends AnyWordSpec with Matchers with BeforeAn val hugePacketSize = 1024 val maxPacketsPerMilli = 3 - "MetricDataPacketBuffer" should { "flush a single metric in one udp packet" in { @@ -26,7 +25,7 @@ class MetricDataPacketBufferSpec extends AnyWordSpec with Matchers with BeforeAn buffer.flush() val packet = statsDServer.getPacket(_.hasMetric(_.name == "counter")) packet.metrics should have size 1 - packet.metrics should contain (Metric("counter", "1.0", "c")) + packet.metrics should contain(Metric("counter", "1.0", "c")) } "flush multiple metrics in the same udp packet" in { @@ -37,8 +36,8 @@ class MetricDataPacketBufferSpec extends AnyWordSpec with Matchers with BeforeAn buffer.flush() val packet = statsDServer.getPacket(_.hasMetric(_.name == "counter")) packet.metrics should have size 2 - packet.metrics should contain (Metric("counter", "1.0", "c")) - packet.metrics should contain (Metric("other_counter", "2.0", "c")) + packet.metrics should contain(Metric("counter", "1.0", "c")) + packet.metrics should contain(Metric("other_counter", "2.0", "c")) } "flush multiple metrics in different udp packets when max packet size is reached" in { @@ -49,10 +48,10 @@ class MetricDataPacketBufferSpec extends AnyWordSpec with Matchers with BeforeAn buffer.flush() val packet = statsDServer.getPacket(_.hasMetric(_.name == "counter")) packet.metrics should have size 1 - packet.metrics should contain (Metric("counter", "1.0", "c")) + packet.metrics should contain(Metric("counter", "1.0", "c")) val otherPacket = statsDServer.getPacket(_.hasMetric(_.name == "other_counter")) otherPacket.metrics should have size 1 - otherPacket.metrics should contain (Metric("other_counter", "2.0", "c")) + otherPacket.metrics should contain(Metric("other_counter", "2.0", "c")) } "flush when max packet size is reached" in { @@ -62,7 +61,7 @@ class MetricDataPacketBufferSpec extends AnyWordSpec with Matchers with BeforeAn buffer.appendMeasurement("other_counter", "2.0|c") val packet = statsDServer.getPacket(_.hasMetric(_.name == "counter")) packet.metrics should have size 1 - packet.metrics should contain (Metric("counter", "1.0", "c")) + packet.metrics should contain(Metric("counter", "1.0", "c")) } "flush same metric in one udp packet because is compressed" in { @@ -75,8 +74,8 @@ class MetricDataPacketBufferSpec extends AnyWordSpec with Matchers with BeforeAn packet.metrics should have size 2 val metrics = packet.metrics.filter(_.name == "counter") metrics should have size 2 - metrics should contain (Metric("counter", "1.0", "c")) - metrics should contain (Metric("counter", "2.0", "c")) + metrics should contain(Metric("counter", "1.0", "c")) + metrics should contain(Metric("counter", "2.0", "c")) } "flush different metric in two udp packets because not compressed" in { @@ -99,8 +98,8 @@ class MetricDataPacketBufferSpec extends AnyWordSpec with Matchers with BeforeAn buffer.appendMeasurement("counter", "3.0|c") buffer.flush() val packets = statsDServer.getPackets(_.size == 2) - packets.exists(_.metrics.size == 2) should be (true) - packets.exists(_.metrics.size == 1) should be (true) + packets.exists(_.metrics.size == 2) should be(true) + packets.exists(_.metrics.size == 1) should be(true) } } diff --git a/reporters/kamon-statsd/src/test/scala/kamon/statsd/ReadConfigUnitSpec.scala b/reporters/kamon-statsd/src/test/scala/kamon/statsd/ReadConfigUnitSpec.scala index fb0854324..f96365c2c 100644 --- a/reporters/kamon-statsd/src/test/scala/kamon/statsd/ReadConfigUnitSpec.scala +++ b/reporters/kamon-statsd/src/test/scala/kamon/statsd/ReadConfigUnitSpec.scala @@ -9,25 +9,25 @@ class ReadConfigUnitSpec extends AnyWordSpec with Matchers { "time unit config" should { "read seconds" in { - readTimeUnit("s") should be (time.seconds) + readTimeUnit("s") should be(time.seconds) } "read milliseconds" in { - readTimeUnit("ms") should be (time.milliseconds) + readTimeUnit("ms") should be(time.milliseconds) } "read microseconds" in { - readTimeUnit("µs") should be (time.microseconds) + readTimeUnit("µs") should be(time.microseconds) } "read nanoseconds" in { - readTimeUnit("ns") should be (time.nanoseconds) + readTimeUnit("ns") should be(time.nanoseconds) } "not read other units" in { - val error = intercept[RuntimeException]{readTimeUnit("h")} - error.getMessage should include ("Invalid time unit") - error.getMessage should include ("[h]") + val error = intercept[RuntimeException] { readTimeUnit("h") } + error.getMessage should include("Invalid time unit") + error.getMessage should include("[h]") } } @@ -35,28 +35,27 @@ class ReadConfigUnitSpec extends AnyWordSpec with Matchers { "information unit config" should { "read bytes" in { - readInformationUnit("b") should be (information.bytes) + readInformationUnit("b") should be(information.bytes) } "read kilobytes" in { - readInformationUnit("kb") should be (information.kilobytes) + readInformationUnit("kb") should be(information.kilobytes) } "read megabytes" in { - readInformationUnit("mb") should be (information.megabytes) + readInformationUnit("mb") should be(information.megabytes) } "read gigabytes" in { - readInformationUnit("gb") should be (information.gigabytes) + readInformationUnit("gb") should be(information.gigabytes) } "not read other units" in { - val error = intercept[RuntimeException]{readInformationUnit("tb")} - error.getMessage should include ("Invalid information unit") - error.getMessage should include ("[tb]") + val error = intercept[RuntimeException] { readInformationUnit("tb") } + error.getMessage should include("Invalid information unit") + error.getMessage should include("[tb]") } } - } diff --git a/reporters/kamon-statsd/src/test/scala/kamon/statsd/SimpleMetricKeyGeneratorSpec.scala b/reporters/kamon-statsd/src/test/scala/kamon/statsd/SimpleMetricKeyGeneratorSpec.scala index 5f166d45d..aec9662d6 100644 --- a/reporters/kamon-statsd/src/test/scala/kamon/statsd/SimpleMetricKeyGeneratorSpec.scala +++ b/reporters/kamon-statsd/src/test/scala/kamon/statsd/SimpleMetricKeyGeneratorSpec.scala @@ -60,8 +60,14 @@ class SimpleMetricKeyGeneratorSpec extends AnyWordSpec with Matchers { val generator = new SimpleMetricKeyGenerator(defaultConfiguration.getConfig("kamon.statsd")) val host = generator.normalizer(Kamon.environment.host) - generator.generateKey("actor", TagSet.from(Map("metric-name-1" -> "/user/example", "metric-name-2" -> "processing-time"))) should be(s"kamon.$host.actor.metric-name-1._user_example.metric-name-2.processing-time") - generator.generateKey("trace", TagSet.from(Map("metric-name-1" -> "POST: /kamon/example", "metric-name-2" -> "elapsed-time"))) should be(s"kamon.$host.trace.metric-name-1.POST-_kamon_example.metric-name-2.elapsed-time") + generator.generateKey( + "actor", + TagSet.from(Map("metric-name-1" -> "/user/example", "metric-name-2" -> "processing-time")) + ) should be(s"kamon.$host.actor.metric-name-1._user_example.metric-name-2.processing-time") + generator.generateKey( + "trace", + TagSet.from(Map("metric-name-1" -> "POST: /kamon/example", "metric-name-2" -> "elapsed-time")) + ) should be(s"kamon.$host.trace.metric-name-1.POST-_kamon_example.metric-name-2.elapsed-time") } "generate metric names with tags sorted by tag name" in { @@ -69,8 +75,12 @@ class SimpleMetricKeyGeneratorSpec extends AnyWordSpec with Matchers { val generator = new SimpleMetricKeyGenerator(defaultConfiguration.getConfig("kamon.statsd")) val host = generator.normalizer(Kamon.environment.host) - generator.generateKey("actor", TagSet.from(Map("tag-1" -> "value-1", "tag-2" -> "value-2"))) should be(s"kamon.$host.actor.tag-1.value-1.tag-2.value-2") - generator.generateKey("actor", TagSet.from(Map("tag-2" -> "value-2", "tag-1" -> "value-1"))) should be(s"kamon.$host.actor.tag-1.value-1.tag-2.value-2") + generator.generateKey("actor", TagSet.from(Map("tag-1" -> "value-1", "tag-2" -> "value-2"))) should be( + s"kamon.$host.actor.tag-1.value-1.tag-2.value-2" + ) + generator.generateKey("actor", TagSet.from(Map("tag-2" -> "value-2", "tag-1" -> "value-1"))) should be( + s"kamon.$host.actor.tag-1.value-1.tag-2.value-2" + ) } "generate metric names with environment tags sorted by tag name" in { @@ -78,8 +88,12 @@ class SimpleMetricKeyGeneratorSpec extends AnyWordSpec with Matchers { val generator = new SimpleMetricKeyGenerator(defaultConfiguration.getConfig("kamon.statsd")) val host = generator.normalizer(Kamon.environment.host) - generator.generateKey("actor", TagSet.from(Map("tag-1" -> "value-1", "tag-2" -> "value-2"))) should be(s"kamon.$host.actor.tag-1.value-1.tag-2.value-2.tag-3.value-3.tag-4.value-4") - generator.generateKey("actor", TagSet.from(Map("tag-2" -> "value-2", "tag-1" -> "value-1"))) should be(s"kamon.$host.actor.tag-1.value-1.tag-2.value-2.tag-3.value-3.tag-4.value-4") + generator.generateKey("actor", TagSet.from(Map("tag-1" -> "value-1", "tag-2" -> "value-2"))) should be( + s"kamon.$host.actor.tag-1.value-1.tag-2.value-2.tag-3.value-3.tag-4.value-4" + ) + generator.generateKey("actor", TagSet.from(Map("tag-2" -> "value-2", "tag-1" -> "value-1"))) should be( + s"kamon.$host.actor.tag-1.value-1.tag-2.value-2.tag-3.value-3.tag-4.value-4" + ) } "generate metric names without tags that follow the application.host.entity.entity-name.metric-name pattern by default" in { @@ -92,31 +106,57 @@ class SimpleMetricKeyGeneratorSpec extends AnyWordSpec with Matchers { "removes host name when attribute 'include-hostname' is set to false" in { Kamon.reconfigure(defaultConfiguration) - val hostOverrideConfig = ConfigFactory.parseString("kamon.statsd.simple-metric-key-generator.include-hostname = false") - val generator = new SimpleMetricKeyGenerator(hostOverrideConfig.withFallback(defaultConfiguration).getConfig("kamon.statsd")) - - generator.generateKey("actor", TagSet.from(Map("metric-name-1" -> "/user/example", "metric-name-2" -> "processing-time"))) should be("kamon.actor.metric-name-1._user_example.metric-name-2.processing-time") - generator.generateKey("trace", TagSet.from(Map("metric-name-1" -> "POST: /kamon/example", "metric-name-2" -> "elapsed-time"))) should be("kamon.trace.metric-name-1.POST-_kamon_example.metric-name-2.elapsed-time") + val hostOverrideConfig = + ConfigFactory.parseString("kamon.statsd.simple-metric-key-generator.include-hostname = false") + val generator = + new SimpleMetricKeyGenerator(hostOverrideConfig.withFallback(defaultConfiguration).getConfig("kamon.statsd")) + + generator.generateKey( + "actor", + TagSet.from(Map("metric-name-1" -> "/user/example", "metric-name-2" -> "processing-time")) + ) should be("kamon.actor.metric-name-1._user_example.metric-name-2.processing-time") + generator.generateKey( + "trace", + TagSet.from(Map("metric-name-1" -> "POST: /kamon/example", "metric-name-2" -> "elapsed-time")) + ) should be("kamon.trace.metric-name-1.POST-_kamon_example.metric-name-2.elapsed-time") } "remove spaces, colons and replace '/' with '_' when the normalization strategy is 'normalize'" in { Kamon.reconfigure(defaultConfiguration) - val hostOverrideConfig = ConfigFactory.parseString("kamon.statsd.simple-metric-key-generator.metric-name-normalization-strategy = normalize") - val generator = new SimpleMetricKeyGenerator(hostOverrideConfig.withFallback(defaultConfiguration).getConfig("kamon.statsd")) + val hostOverrideConfig = ConfigFactory.parseString( + "kamon.statsd.simple-metric-key-generator.metric-name-normalization-strategy = normalize" + ) + val generator = + new SimpleMetricKeyGenerator(hostOverrideConfig.withFallback(defaultConfiguration).getConfig("kamon.statsd")) val host = generator.normalizer(Kamon.environment.host) - generator.generateKey("actor", TagSet.from(Map("metric-name-1" -> "/user/example", "metric-name-2" -> "processing-time"))) should be(s"kamon.$host.actor.metric-name-1._user_example.metric-name-2.processing-time") - generator.generateKey("trace", TagSet.from(Map("metric-name-1" -> "POST: /kamon/example", "metric-name-2" -> "elapsed-time"))) should be(s"kamon.$host.trace.metric-name-1.POST-_kamon_example.metric-name-2.elapsed-time") + generator.generateKey( + "actor", + TagSet.from(Map("metric-name-1" -> "/user/example", "metric-name-2" -> "processing-time")) + ) should be(s"kamon.$host.actor.metric-name-1._user_example.metric-name-2.processing-time") + generator.generateKey( + "trace", + TagSet.from(Map("metric-name-1" -> "POST: /kamon/example", "metric-name-2" -> "elapsed-time")) + ) should be(s"kamon.$host.trace.metric-name-1.POST-_kamon_example.metric-name-2.elapsed-time") } "percent-encode special characters in the group name and hostname when the normalization strategy is 'normalize'" in { Kamon.reconfigure(defaultConfiguration) - val hostOverrideConfig = ConfigFactory.parseString("kamon.statsd.simple-metric-key-generator.metric-name-normalization-strategy = percent-encode") - val generator = new SimpleMetricKeyGenerator(hostOverrideConfig.withFallback(defaultConfiguration).getConfig("kamon.statsd")) + val hostOverrideConfig = ConfigFactory.parseString( + "kamon.statsd.simple-metric-key-generator.metric-name-normalization-strategy = percent-encode" + ) + val generator = + new SimpleMetricKeyGenerator(hostOverrideConfig.withFallback(defaultConfiguration).getConfig("kamon.statsd")) val host = generator.normalizer(Kamon.environment.host) - generator.generateKey("actor", TagSet.from(Map("metric-name-1" -> "/user/example", "metric-name-2" -> "processing-time"))) should be(s"kamon.$host.actor.metric-name-1.%2Fuser%2Fexample.metric-name-2.processing-time") - generator.generateKey("trace", TagSet.from(Map("metric-name-1" -> "POST: /kamon/example", "metric-name-2" -> "elapsed-time"))) should be(s"kamon.$host.trace.metric-name-1.POST%3A%20%2Fkamon%2Fexample.metric-name-2.elapsed-time") + generator.generateKey( + "actor", + TagSet.from(Map("metric-name-1" -> "/user/example", "metric-name-2" -> "processing-time")) + ) should be(s"kamon.$host.actor.metric-name-1.%2Fuser%2Fexample.metric-name-2.processing-time") + generator.generateKey( + "trace", + TagSet.from(Map("metric-name-1" -> "POST: /kamon/example", "metric-name-2" -> "elapsed-time")) + ) should be(s"kamon.$host.trace.metric-name-1.POST%3A%20%2Fkamon%2Fexample.metric-name-2.elapsed-time") } } diff --git a/reporters/kamon-statsd/src/test/scala/kamon/statsd/StatsDReporterSpec.scala b/reporters/kamon-statsd/src/test/scala/kamon/statsd/StatsDReporterSpec.scala index 5d93147a3..ecc24d3e4 100644 --- a/reporters/kamon-statsd/src/test/scala/kamon/statsd/StatsDReporterSpec.scala +++ b/reporters/kamon-statsd/src/test/scala/kamon/statsd/StatsDReporterSpec.scala @@ -36,7 +36,7 @@ class StatsDReporterSpec extends AnyWordSpec with Matchers with BeforeAndAfter w val statsDServer = new StatsDServer() val config: Config = ConfigFactory.parseString( - s""" + s""" |kamon { | statsd { | hostname = "127.0.0.1" @@ -55,7 +55,7 @@ class StatsDReporterSpec extends AnyWordSpec with Matchers with BeforeAndAfter w |} | """.stripMargin - ) + ) val metricKeyGenerator = new SimpleMetricKeyGenerator(config.getConfig("kamon.statsd")) val testConfig: Config = ConfigFactory.load(config).withFallback(ConfigFactory.load()) val statsDReporter = new TestStatsDReporter() @@ -63,7 +63,7 @@ class StatsDReporterSpec extends AnyWordSpec with Matchers with BeforeAndAfter w "the StatsDReporterSpec" should { - "flush the gauge metric data it receives" in { + "flush the gauge metric data it receives" in { val name = generateMetricName() statsDReporter.waitForNextSnapshot() @@ -71,47 +71,47 @@ class StatsDReporterSpec extends AnyWordSpec with Matchers with BeforeAndAfter w val packet = statsDServer.getPacket(_.metrics.exists(_.name.contains(name))) val metric = packet.getMetric(_.name == name.asMetricName) - metric.value should be (Metric(name.asMetricName, "1.0", Gauge, None)) + metric.value should be(Metric(name.asMetricName, "1.0", Gauge, None)) } - "flush the counter metric data it receives" in { + "flush the counter metric data it receives" in { val name = generateMetricName() statsDReporter.waitForNextSnapshot() Kamon.counter(name).withoutTags().increment(3) val packet = statsDServer.getPacket(_.metrics.exists(_.name.contains(name))) val metric = packet.getMetric(_.name == name.asMetricName) - metric.value should be (Metric(name.asMetricName, "3.0", Counter, None)) + metric.value should be(Metric(name.asMetricName, "3.0", Counter, None)) } - "flush the histogram metric data it receives" in { + "flush the histogram metric data it receives" in { val name = generateMetricName() statsDReporter.waitForNextSnapshot() Kamon.histogram(name).withoutTags().record(2) val packet = statsDServer.getPacket(_.metrics.exists(_.name.contains(name))) val metric = packet.getMetric(_.name == name.asMetricName) - metric.value should be (Metric(name.asMetricName, "2.0", Timer, None)) + metric.value should be(Metric(name.asMetricName, "2.0", Timer, None)) } - "convert time metric in milliseconds before flushing it" in { + "convert time metric in milliseconds before flushing it" in { val name = generateMetricName() statsDReporter.waitForNextSnapshot() Kamon.histogram(name, MeasurementUnit.time.seconds).withoutTags().record(1) val packet = statsDServer.getPacket(_.metrics.exists(_.name.contains(name))) val metric = packet.getMetric(_.name == name.asMetricName) - metric.value should be (Metric(name.asMetricName, "1000.0", Timer, None)) + metric.value should be(Metric(name.asMetricName, "1000.0", Timer, None)) } - "convert information metric in byte before flushing it" in { + "convert information metric in byte before flushing it" in { val name = generateMetricName() statsDReporter.waitForNextSnapshot() Kamon.histogram(name, MeasurementUnit.information.kilobytes).withoutTags().record(1) val packet = statsDServer.getPacket(_.metrics.exists(_.name.contains(name))) val metric = packet.getMetric(_.name == name.asMetricName) - metric.value should be (Metric(name.asMetricName, "1024.0", Timer, None)) + metric.value should be(Metric(name.asMetricName, "1024.0", Timer, None)) } } diff --git a/reporters/kamon-statsd/src/test/scala/kamon/statsd/StatsDServer.scala b/reporters/kamon-statsd/src/test/scala/kamon/statsd/StatsDServer.scala index 9ee9dae97..d8b1274eb 100644 --- a/reporters/kamon-statsd/src/test/scala/kamon/statsd/StatsDServer.scala +++ b/reporters/kamon-statsd/src/test/scala/kamon/statsd/StatsDServer.scala @@ -129,4 +129,4 @@ object StatsDServer { } } -} \ No newline at end of file +} diff --git a/reporters/kamon-zipkin/src/main/scala/kamon/zipkin/ZipkinReporter.scala b/reporters/kamon-zipkin/src/main/scala/kamon/zipkin/ZipkinReporter.scala index 2cf909e5e..7020b9004 100644 --- a/reporters/kamon-zipkin/src/main/scala/kamon/zipkin/ZipkinReporter.scala +++ b/reporters/kamon-zipkin/src/main/scala/kamon/zipkin/ZipkinReporter.scala @@ -48,7 +48,7 @@ class ZipkinReporter(configPath: String) extends SpanReporter { def checkJoinParameter() = { val joinRemoteParentsWithSameID = Kamon.config().getBoolean("kamon.trace.join-remote-parents-with-same-span-id") - if(!joinRemoteParentsWithSameID) + if (!joinRemoteParentsWithSameID) _logger.warn("For full Zipkin compatibility enable `kamon.trace.join-remote-parents-with-same-span-id` to " + "preserve span id across client/server sides of a Span.") } @@ -72,14 +72,14 @@ class ZipkinReporter(configPath: String) extends SpanReporter { val kind = spanKind(kamonSpan) builder.kind(kind) - if(kind == ZipkinSpan.Kind.CLIENT) { + if (kind == ZipkinSpan.Kind.CLIENT) { val remoteEndpoint = Endpoint.newBuilder() .ip(getStringTag(kamonSpan, PeerKeys.IPv4)) .ip(getStringTag(kamonSpan, PeerKeys.IPv6)) .port(getLongTag(kamonSpan, PeerKeys.Port).toInt) .build() - if(hasAnyData(remoteEndpoint)) + if (hasAnyData(remoteEndpoint)) builder.remoteEndpoint(remoteEndpoint) } @@ -98,12 +98,14 @@ class ZipkinReporter(configPath: String) extends SpanReporter { case Span.Kind.Server => ZipkinSpan.Kind.SERVER case Span.Kind.Producer => ZipkinSpan.Kind.PRODUCER case Span.Kind.Consumer => ZipkinSpan.Kind.CONSUMER - case _ => null + case _ => null } private def addTags(tags: TagSet, builder: ZipkinSpan.Builder): Unit = tags.iterator(_.toString) - .filterNot(pair => pair.key == Span.TagKeys.Error && pair.value == "false") // zipkin considers any error tag as failed request + .filterNot(pair => + pair.key == Span.TagKeys.Error && pair.value == "false" + ) // zipkin considers any error tag as failed request .foreach(pair => builder.putTag(pair.key, pair.value)) private def getStringTag(span: Span.Finished, tagName: String): String = @@ -112,11 +114,9 @@ class ZipkinReporter(configPath: String) extends SpanReporter { private def getLongTag(span: Span.Finished, tagName: String): Long = span.tags.get(longOption(tagName)).orElse(span.metricTags.get(longOption(tagName))).getOrElse(0L) - private def hasAnyData(endpoint: Endpoint): Boolean = endpoint.ipv4() != null || endpoint.ipv6() != null || endpoint.port() != null || endpoint.serviceName() != null - override def reconfigure(newConfig: Config): Unit = { _localEndpoint = buildEndpoint() _reporter = buildReporter(newConfig) @@ -153,9 +153,9 @@ object ZipkinReporter { } private object PeerKeys { - val Host = "peer.host" - val Port = "peer.port" - val IPv4 = "peer.ipv4" - val IPv6 = "peer.ipv6" + val Host = "peer.host" + val Port = "peer.port" + val IPv4 = "peer.ipv4" + val IPv6 = "peer.ipv6" } } diff --git a/reporters/kamon-zipkin/src/test/scala/kamon/zipkin/SpanConversionSpec.scala b/reporters/kamon-zipkin/src/test/scala/kamon/zipkin/SpanConversionSpec.scala index b7e8386bb..6cf510441 100644 --- a/reporters/kamon-zipkin/src/test/scala/kamon/zipkin/SpanConversionSpec.scala +++ b/reporters/kamon-zipkin/src/test/scala/kamon/zipkin/SpanConversionSpec.scala @@ -98,7 +98,6 @@ class SpanConversionSpec extends AnyWordSpec with Matchers { def newSpan(operationName: String = "test-span"): FinishedSpanBuilder = new FinishedSpanBuilder(operationName) - class FinishedSpanBuilder(operationName: String) { var span = Span.Finished( id = Identifier("0000000000000002", Array[Byte](2)), @@ -139,7 +138,7 @@ class SpanConversionSpec extends AnyWordSpec with Matchers { def hasError(error: Boolean): FinishedSpanBuilder = { span = span.copy(hasError = error) - if(error) + if (error) trueTag(Span.TagKeys.Error) else falseTag(Span.TagKeys.Error) From a87cc88cdaea926e5b4cdc9719cf88636636d1ef Mon Sep 17 00:00:00 2001 From: Hugh Simpson Date: Sat, 2 Mar 2024 15:36:28 +0000 Subject: [PATCH 3/5] ignore blame for fmt --- .git-blame-ignore-revs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index e69de29bb..985b60b4d 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -0,0 +1,2 @@ +# Initial scalafmtAll was applied +022216d6b1ebe4dd0c00aef204625f7f3372fc90 From 1281fb40c22bf30ccfcbef4397e5ad3081d85589 Mon Sep 17 00:00:00 2001 From: Hugh Simpson Date: Sat, 2 Mar 2024 15:43:30 +0000 Subject: [PATCH 4/5] add lint check --- .github/workflows/ci.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 042e40690..fb608ca8d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,6 +1,6 @@ name: Test all the things -on: [push, pull_request] +on: [ push, pull_request ] jobs: ci: @@ -18,3 +18,10 @@ jobs: apps: sbt - name: Test run: sbt -v ";+core/test;+instrumentation/test;+reporters/test" + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - name: Test + run: sbt -v "scalafmtCheckAll" + From db6527d87f01a36288e0a9ed1027ba6db2c8f88b Mon Sep 17 00:00:00 2001 From: Hugh Simpson Date: Sat, 2 Mar 2024 15:44:29 +0000 Subject: [PATCH 5/5] cache --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fb608ca8d..921a8f4f4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,6 +22,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 + - uses: coursier/cache-action@v6 - name: Test run: sbt -v "scalafmtCheckAll"