feat(otel): add custom OpenTelemetry module with tracing, metrics, and structured logging#1226
Open
feat(otel): add custom OpenTelemetry module with tracing, metrics, and structured logging#1226
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
Adds a new otel subproject implementing OpenTelemetry-style tracing, metrics, and structured logging (with OTLP/JSON export) directly in zio-blocks.
Changes:
- Introduces core OTel data model + APIs (Tracer/Span, Meter/instruments, Logger/log records) with context propagation (W3C + B3) and runtime Loom-aware context storage.
- Adds OTLP/JSON exporters with batching, retries, and a platform scheduler.
- Adds extensive test suite for IDs, context storage, samplers, spans, instruments, exporters, and SDK wiring; updates
build.sbtto include the new module.
Reviewed changes
Copilot reviewed 68 out of 69 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| build.sbt | Adds otel project, dependencies, coverage thresholds, and test alias integration. |
| otel/src/main/scala/zio/blocks/otel/AttributeKey.scala | Defines typed attribute keys used across all signals. |
| otel/src/main/scala/zio/blocks/otel/AttributeType.scala | Adds attribute type discriminator used for key/value conversion. |
| otel/src/main/scala/zio/blocks/otel/AttributeValue.scala | Adds attribute value ADT (scalar + seq) used by Attributes and signal payloads. |
| otel/src/main/scala/zio/blocks/otel/Attributes.scala | Implements immutable Attributes and builder used across spans/logs/metrics. |
| otel/src/main/scala/zio/blocks/otel/B3Propagator.scala | Implements B3 single and multi-header context propagation. |
| otel/src/main/scala/zio/blocks/otel/BatchProcessor.scala | Adds batching/retry processor used by OTLP exporters. |
| otel/src/main/scala/zio/blocks/otel/ContextStorage.scala | Adds Loom-aware context storage (ScopedValue via reflection; ThreadLocal fallback). |
| otel/src/main/scala/zio/blocks/otel/HttpSender.scala | Adds HTTP transport abstraction + JDK HttpClient sender for OTLP exports. |
| otel/src/main/scala/zio/blocks/otel/InstrumentationScope.scala | Defines instrumentation scope metadata for produced telemetry. |
| otel/src/main/scala/zio/blocks/otel/Logger.scala | Implements structured logging with optional trace correlation from ContextStorage. |
| otel/src/main/scala/zio/blocks/otel/LoggerProvider.scala | Provides Logger instances and configures processors + context storage. |
| otel/src/main/scala/zio/blocks/otel/LogRecord.scala | Defines LogRecord data model and a builder for log emission. |
| otel/src/main/scala/zio/blocks/otel/LogRecordProcessor.scala | Defines log processor interface + noop implementation. |
| otel/src/main/scala/zio/blocks/otel/Meter.scala | Implements Meter + builders and ties instruments into collection registry. |
| otel/src/main/scala/zio/blocks/otel/MeterProvider.scala | Provides meters and reader backed by a shared registry. |
| otel/src/main/scala/zio/blocks/otel/MetricData.scala | Defines metric point types and MetricData ADT. |
| otel/src/main/scala/zio/blocks/otel/MetricReader.scala | Defines metric reader API + default impl. |
| otel/src/main/scala/zio/blocks/otel/ObservableInstruments.scala | Adds observable instruments and callback API. |
| otel/src/main/scala/zio/blocks/otel/OtelContext.scala | Bridges ContextStorage with zio-blocks Context[R]. |
| otel/src/main/scala/zio/blocks/otel/OtelExample.scala | Adds example main program demonstrating tracing/metrics/logging usage. |
| otel/src/main/scala/zio/blocks/otel/OtelSdk.scala | Adds SDK builder wiring exporters, providers, scheduler, and shutdown hook. |
| otel/src/main/scala/zio/blocks/otel/OtlpJsonExporter.scala | Adds OTLP/JSON exporter config and trace/log/metric exporters. |
| otel/src/main/scala/zio/blocks/otel/PlatformExecutor.scala | Provides scheduled executor using virtual threads when available. |
| otel/src/main/scala/zio/blocks/otel/Propagator.scala | Defines propagation abstraction (extract/inject + fields). |
| otel/src/main/scala/zio/blocks/otel/Resource.scala | Defines Resource model and default resource attributes. |
| otel/src/main/scala/zio/blocks/otel/Sampler.scala | Defines sampler API and implementations (AlwaysOn/Off/ParentBased). |
| otel/src/main/scala/zio/blocks/otel/Severity.scala | Defines 24-level severity model and parsing helpers. |
| otel/src/main/scala/zio/blocks/otel/Span.scala | Defines Span API + RecordingSpan implementation and NoOp span. |
| otel/src/main/scala/zio/blocks/otel/SpanBuilder.scala | Adds fluent span builder to create RecordingSpan instances. |
| otel/src/main/scala/zio/blocks/otel/SpanContext.scala | Adds SpanContext model (TraceId/SpanId/flags/state/remote). |
| otel/src/main/scala/zio/blocks/otel/SpanData.scala | Defines immutable span snapshot model (events/links/status/resource/scope). |
| otel/src/main/scala/zio/blocks/otel/SpanId.scala | Adds SpanId model + parsing/formatting + random generation. |
| otel/src/main/scala/zio/blocks/otel/SpanKind.scala | Adds span kind ADT (internal/server/client/producer/consumer). |
| otel/src/main/scala/zio/blocks/otel/SpanProcessor.scala | Defines span processor interface + noop implementation. |
| otel/src/main/scala/zio/blocks/otel/SpanStatus.scala | Adds span status ADT (Unset/Ok/Error). |
| otel/src/main/scala/zio/blocks/otel/SyncInstruments.scala | Implements sync instruments (Counter, UpDownCounter, Histogram, Gauge). |
| otel/src/main/scala/zio/blocks/otel/TraceFlags.scala | Adds trace flags model + hex parsing/formatting. |
| otel/src/main/scala/zio/blocks/otel/TraceId.scala | Adds TraceId model + hex parsing/formatting + random generation. |
| otel/src/main/scala/zio/blocks/otel/Tracer.scala | Adds Tracer API with scoped span block pattern and processor callbacks. |
| otel/src/main/scala/zio/blocks/otel/TracerProvider.scala | Adds TracerProvider builder and lifecycle methods. |
| otel/src/main/scala/zio/blocks/otel/W3CTraceContextPropagator.scala | Implements W3C traceparent/tracestate propagator. |
| otel/src/test/scala/zio/blocks/otel/BatchProcessorSpec.scala | Tests batching, drops, retries, periodic flush behavior. |
| otel/src/test/scala/zio/blocks/otel/ContextStorageSpec.scala | Tests ScopedValue/ThreadLocal behavior and scoped restoration semantics. |
| otel/src/test/scala/zio/blocks/otel/HttpSenderSpec.scala | Tests HttpResponse and JdkHttpSender construction/shutdown behavior. |
| otel/src/test/scala/zio/blocks/otel/InstrumentationScopeSpec.scala | Tests InstrumentationScope constructors, accessors, and equality behavior. |
| otel/src/test/scala/zio/blocks/otel/LogRecordSpec.scala | Tests LogRecord model, builder, severity mapping/parsing, and trace fields. |
| otel/src/test/scala/zio/blocks/otel/LoggerSpec.scala | Tests logging pipeline, convenience APIs, and trace correlation behavior. |
| otel/src/test/scala/zio/blocks/otel/MeterSpec.scala | Tests sync + observable instruments and reader collection across meters. |
| otel/src/test/scala/zio/blocks/otel/OtelContextSpec.scala | Tests OtelContext snapshot/withSpan and integration with zio-blocks Context. |
| otel/src/test/scala/zio/blocks/otel/OtelSdkSpec.scala | Tests SDK builder wiring, providers, resource/sampler customization, shutdown. |
| otel/src/test/scala/zio/blocks/otel/PlatformExecutorSpec.scala | Tests scheduling behavior and cancellation with sequential aspect. |
| otel/src/test/scala/zio/blocks/otel/ResourceSpec.scala | Tests Resource default attributes and merge semantics. |
| otel/src/test/scala/zio/blocks/otel/SamplerSpec.scala | Tests sampler decisions, descriptions, and parent-based behavior. |
| otel/src/test/scala/zio/blocks/otel/SpanContextSpec.scala | Tests SpanContext validity, sampled flag, and equality/immutability intent. |
| otel/src/test/scala/zio/blocks/otel/SpanIdSpec.scala | Tests SpanId parsing/formatting, validity rules, random generation. |
| otel/src/test/scala/zio/blocks/otel/SpanKindSpec.scala | Tests SpanKind sealing/exhaustiveness and equality behavior. |
| otel/src/test/scala/zio/blocks/otel/SpanSpec.scala | Tests RecordingSpan lifecycle, NoOp behavior, builder behavior, concurrency. |
| otel/src/test/scala/zio/blocks/otel/SpanStatusSpec.scala | Tests SpanStatus ADT correctness and pattern matching behavior. |
| otel/src/test/scala/zio/blocks/otel/TraceFlagsSpec.scala | Tests TraceFlags parsing/formatting and bit semantics. |
| otel/src/test/scala/zio/blocks/otel/TraceIdSpec.scala | Tests TraceId parsing/formatting, validity rules, random generation. |
| otel/src/test/scala/zio/blocks/otel/TracerSpec.scala | Tests tracer provider builder, scoped span behavior, nesting, sampling. |
Comments suppressed due to low confidence (2)
otel/src/main/scala/zio/blocks/otel/Tracer.scala:1
SamplingResultis computed but not fully applied: (1)SamplingDecision.RecordOnlyis treated the same asRecordAndSample, so spans that should be “record only” still look sampled/exportable; (2)SamplingResult.attributesandSamplingResult.traceStateare ignored. This will break sampler behavior (especially ParentBased + RecordOnly) and any sampler-provided attributes/state. Apply the sampler outcome by setting the resulting trace flags/trace state on the createdSpanContext, mergingresult.attributesinto the span’s initial attributes, and ensuringRecordOnlyresults inTraceFlags.none(and/or suppresses export if that’s the intended behavior).
otel/src/main/scala/zio/blocks/otel/SyncInstruments.scala:1- The
Counterdocs say it “only allows non-negative additions,” butadddoes not enforcevalue >= 0. Either enforce monotonicity (e.g., ignore/throw on negative values) or update the documentation to match the actual behavior; otherwise callers can record invalid counter semantics.
Comment on lines
+74
to
+114
| val contextStorage = ContextStorage.create[Option[SpanContext]](None) | ||
| val sdkScope = InstrumentationScope("otel-sdk") | ||
|
|
||
| // Trace exporter as a SpanProcessor | ||
| val traceExporter = new OtlpJsonTraceExporter(exporterConfig, resource, sdkScope, httpSender) | ||
| val tracerProvider = TracerProvider.builder | ||
| .setResource(resource) | ||
| .setSampler(sampler) | ||
| .addSpanProcessor(traceExporter) | ||
| .build() | ||
|
|
||
| // Meter provider | ||
| val meterProvider = MeterProvider.builder | ||
| .setResource(resource) | ||
| .build() | ||
|
|
||
| // Schedule periodic metric export | ||
| val metricExporter = new OtlpJsonMetricExporter( | ||
| exporterConfig, | ||
| resource, | ||
| sdkScope, | ||
| httpSender, | ||
| () => | ||
| meterProvider.reader.collectAllMetrics().map { data => | ||
| NamedMetric("metric", "", "", data) | ||
| } | ||
| ) | ||
|
|
||
| PlatformExecutor.schedule( | ||
| exporterConfig.flushIntervalMillis, | ||
| exporterConfig.flushIntervalMillis, | ||
| TimeUnit.MILLISECONDS | ||
| )(new Runnable { def run(): Unit = { metricExporter.exportMetrics(); () } }) | ||
|
|
||
| // Logger provider with log exporter | ||
| val logExporter = new OtlpJsonLogExporter(exporterConfig, resource, sdkScope, httpSender) | ||
| val loggerProvider = LoggerProvider.builder | ||
| .setResource(resource) | ||
| .addLogRecordProcessor(logExporter) | ||
| .setContextStorage(contextStorage) | ||
| .build() |
Comment on lines
+191
to
+192
| resource = Resource.empty, | ||
| instrumentationScope = InstrumentationScope("default") |
| * This builder for method chaining | ||
| */ | ||
| def setAttribute[A](key: AttributeKey[A], value: A): LogRecordBuilder = | ||
| copy(attributes = Attributes.builder.put(key, value).build) |
Comment on lines
+102
to
+106
| PlatformExecutor.schedule( | ||
| exporterConfig.flushIntervalMillis, | ||
| exporterConfig.flushIntervalMillis, | ||
| TimeUnit.MILLISECONDS | ||
| )(new Runnable { def run(): Unit = { metricExporter.exportMetrics(); () } }) |
Comment on lines
+1
to
+5
| package zio.blocks.otel | ||
|
|
||
| import java.net.URI | ||
| import java.net.http.{HttpClient, HttpRequest, HttpResponse => JdkHttpResponse} | ||
| import java.time.Duration |
159251f to
43b0bfe
Compare
…d structured logging Custom OTel implementation for zio-blocks — no Java SDK dependency. Tracing: TraceId, SpanId, Span, SpanContext, Tracer with scoped block pattern, TracerProvider, SpanProcessor, Sampler (AlwaysOn/AlwaysOff/ParentBased) Metrics: Counter (monotonic, enforces non-negative), UpDownCounter, Histogram, Gauge (sync), ObservableCounter, ObservableUpDownCounter, ObservableGauge (async), Meter, MeterProvider Logging: Severity (24 levels), LogRecord, Logger with trace correlation, LoggerProvider, LogRecordProcessor Context: Loom-aware ContextStorage (ScopedValue + ThreadLocal fallback via reflection), shared between TracerProvider and LoggerProvider for trace correlation, PlatformExecutor (virtual threads on JDK 21+, daemon fallback), OtelContext integration with zio-blocks Context[R] Propagation: W3C TraceContext (traceparent/tracestate), B3 (single + multi-header) Export: OTLP/JSON encoding, HttpSender + JdkHttpSender, BatchProcessor with bounded queue and retry, OtlpJsonExporter for all three signals SDK: OtelSdk builder entry point with proper lifecycle management 580 tests, 87.6% statement / 72.6% branch coverage
Contributor
There was a problem hiding this comment.
Pull request overview
Adds a new JVM-only otel module to zio-blocks that implements core OpenTelemetry signals (tracing, metrics, structured logging), context propagation, and OTLP/JSON export without relying on the Java OTel SDK.
Changes:
- Introduces tracing primitives (IDs, span context/kind/status, span builder/impl), sampling, and propagators (W3C + B3).
- Adds metrics API (sync + observable instruments), collection/reader infrastructure, and periodic export wiring.
- Adds structured logging with trace correlation plus batching/export plumbing; wires everything through an
OtelSdkbuilder and updatesbuild.sbtto include the new project and tests.
Reviewed changes
Copilot reviewed 74 out of 79 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| build.sbt | Adds otel project definition, test alias integration, and coverage configuration. |
| otel/src/main/scala/zio/blocks/otel/AttributeKey.scala | Defines typed attribute keys for telemetry attributes. |
| otel/src/main/scala/zio/blocks/otel/AttributeType.scala | Defines attribute type discriminators. |
| otel/src/main/scala/zio/blocks/otel/AttributeValue.scala | Defines the attribute value ADT. |
| otel/src/main/scala/zio/blocks/otel/Attributes.scala | Implements immutable attributes collection + builder utilities. |
| otel/src/main/scala/zio/blocks/otel/B3Propagator.scala | Implements B3 single/multi-header propagation. |
| otel/src/main/scala/zio/blocks/otel/BatchProcessor.scala | Adds batching, queueing, flushing, and retry logic for exports. |
| otel/src/main/scala/zio/blocks/otel/ContextStorage.scala | Adds Loom-aware scoped context storage (ScopedValue/ThreadLocal). |
| otel/src/main/scala/zio/blocks/otel/HttpSender.scala | Provides HTTP sender abstraction and JDK HttpClient implementation. |
| otel/src/main/scala/zio/blocks/otel/InstrumentationScope.scala | Defines instrumentation scope model. |
| otel/src/main/scala/zio/blocks/otel/LogRecord.scala | Adds log record model + builder. |
| otel/src/main/scala/zio/blocks/otel/LogRecordProcessor.scala | Adds log processor API + noop implementation. |
| otel/src/main/scala/zio/blocks/otel/Logger.scala | Implements structured logger with optional trace correlation. |
| otel/src/main/scala/zio/blocks/otel/LoggerProvider.scala | Provides loggers by instrumentation scope and manages processors. |
| otel/src/main/scala/zio/blocks/otel/Meter.scala | Implements meter/instrument builders and internal registry collection. |
| otel/src/main/scala/zio/blocks/otel/MeterProvider.scala | Provides meters and a metric reader backed by a registry. |
| otel/src/main/scala/zio/blocks/otel/MetricData.scala | Defines metric data models (sum/histogram/gauge). |
| otel/src/main/scala/zio/blocks/otel/MetricReader.scala | Defines metric reader API and default implementation. |
| otel/src/main/scala/zio/blocks/otel/ObservableInstruments.scala | Adds observable instrument types and callback collection. |
| otel/src/main/scala/zio/blocks/otel/OtelContext.scala | Bridges otel context storage with zio-blocks Context[R]. |
| otel/src/main/scala/zio/blocks/otel/OtelExample.scala | Demonstrates end-to-end usage of tracing/metrics/logging. |
| otel/src/main/scala/zio/blocks/otel/OtelSdk.scala | Adds SDK builder wiring exporters/providers and scheduling metric export. |
| otel/src/main/scala/zio/blocks/otel/OtlpJsonExporter.scala | Adds OTLP/JSON exporter config and exporters for traces/logs/metrics. |
| otel/src/main/scala/zio/blocks/otel/PlatformExecutor.scala | Provides platform executor (virtual threads when available). |
| otel/src/main/scala/zio/blocks/otel/Propagator.scala | Defines the propagation abstraction (extract/inject + fields). |
| otel/src/main/scala/zio/blocks/otel/Resource.scala | Defines OTel Resource model + default attributes and merge support. |
| otel/src/main/scala/zio/blocks/otel/Sampler.scala | Adds sampling decisions, results, and built-in samplers. |
| otel/src/main/scala/zio/blocks/otel/Severity.scala | Adds log severity model and parsing helpers. |
| otel/src/main/scala/zio/blocks/otel/Span.scala | Defines Span API + noop span + recording span implementation. |
| otel/src/main/scala/zio/blocks/otel/SpanBuilder.scala | Implements fluent span builder. |
| otel/src/main/scala/zio/blocks/otel/SpanContext.scala | Defines propagatable span context model and constructors. |
| otel/src/main/scala/zio/blocks/otel/SpanData.scala | Defines export snapshot types (span data, events, links). |
| otel/src/main/scala/zio/blocks/otel/SpanId.scala | Implements span ID generation/validation and hex/bytes conversion. |
| otel/src/main/scala/zio/blocks/otel/SpanKind.scala | Defines span kind ADT. |
| otel/src/main/scala/zio/blocks/otel/SpanProcessor.scala | Defines span processor API + noop implementation. |
| otel/src/main/scala/zio/blocks/otel/SpanStatus.scala | Defines span status ADT. |
| otel/src/main/scala/zio/blocks/otel/SyncInstruments.scala | Implements sync metric instruments (counter/updown/histogram/gauge). |
| otel/src/main/scala/zio/blocks/otel/TraceFlags.scala | Implements trace flags model and hex parsing/formatting. |
| otel/src/main/scala/zio/blocks/otel/TraceId.scala | Implements trace ID generation/validation and hex/bytes conversion. |
| otel/src/main/scala/zio/blocks/otel/Tracer.scala | Implements scoped span lifecycle API with sampler integration. |
| otel/src/main/scala/zio/blocks/otel/TracerProvider.scala | Provides tracers, builder configuration, and processor lifecycle. |
| otel/src/main/scala/zio/blocks/otel/W3CTraceContextPropagator.scala | Implements W3C TraceContext propagation (traceparent/tracestate). |
| otel/src/test/scala/zio/blocks/otel/BatchProcessorSpec.scala | Tests batching, queue bounds, retries, and periodic flush behavior. |
| otel/src/test/scala/zio/blocks/otel/ContextStorageSpec.scala | Tests ScopedValue/ThreadLocal behavior and scoped restoration. |
| otel/src/test/scala/zio/blocks/otel/HttpSenderSpec.scala | Tests HTTP sender/response construction and shutdown behavior. |
| otel/src/test/scala/zio/blocks/otel/InstrumentationScopeSpec.scala | Tests scope constructors/accessors and basic properties. |
| otel/src/test/scala/zio/blocks/otel/LoggerSpec.scala | Tests logging pipeline, severity helpers, and trace correlation. |
| otel/src/test/scala/zio/blocks/otel/MeterSpec.scala | Tests sync + observable instrument collection and provider behavior. |
| otel/src/test/scala/zio/blocks/otel/OtelContextSpec.scala | Tests integration between ContextStorage and zio-blocks Context. |
| otel/src/test/scala/zio/blocks/otel/OtelSdkSpec.scala | Tests SDK builder defaults, provider integration, and shutdown. |
| otel/src/test/scala/zio/blocks/otel/PlatformExecutorSpec.scala | Tests scheduling behavior and cancellation. |
| otel/src/test/scala/zio/blocks/otel/ResourceSpec.scala | Tests resource defaults and merge semantics. |
| otel/src/test/scala/zio/blocks/otel/SamplerSpec.scala | Tests built-in samplers and sampling decisions/results. |
| otel/src/test/scala/zio/blocks/otel/SpanContextSpec.scala | Tests span context validity, sampling flag, and fields. |
| otel/src/test/scala/zio/blocks/otel/SpanIdSpec.scala | Tests span ID parsing/formatting/randomness and bytes conversion. |
| otel/src/test/scala/zio/blocks/otel/SpanKindSpec.scala | Tests span kind accessibility and match exhaustiveness. |
| otel/src/test/scala/zio/blocks/otel/SpanSpec.scala | Tests span lifecycle, data snapshotting, and basic thread-safety. |
| otel/src/test/scala/zio/blocks/otel/SpanStatusSpec.scala | Tests span status variants and pattern matching. |
| otel/src/test/scala/zio/blocks/otel/TraceFlagsSpec.scala | Tests trace flags parsing/formatting and sampled bit operations. |
| otel/src/test/scala/zio/blocks/otel/TraceIdSpec.scala | Tests trace ID parsing/formatting/randomness and bytes conversion. |
Comment on lines
+142
to
+146
| val span = builder.startSpan() | ||
| // Apply traceState from SamplingResult if present | ||
| val finalSpan = if (result.traceState.nonEmpty) { | ||
| val correctedCtx = span.spanContext.copy(traceState = result.traceState) | ||
| new RecordingSpan( |
Comment on lines
+57
to
+61
| val cb = new ObservableCallback { | ||
| def record(value: Double, attributes: Attributes): Unit = { | ||
| measurements.add(SumDataPoint(attributes, 0L, now, value.toLong)) | ||
| () | ||
| } |
Comment on lines
+19
to
+33
| final class TracerProvider( | ||
| resource: Resource, | ||
| sampler: Sampler, | ||
| processors: Seq[SpanProcessor], | ||
| private[otel] val contextStorage: ContextStorage[Option[SpanContext]] | ||
| ) { | ||
|
|
||
| def get(name: String, version: String = ""): Tracer = { | ||
| val scope = InstrumentationScope( | ||
| name = name, | ||
| version = if (version.isEmpty) None else Some(version) | ||
| ) | ||
| new Tracer(scope, resource, sampler, processors, contextStorage) | ||
| } | ||
|
|
Comment on lines
+198
to
+203
| seq.headOption match { | ||
| case Some(_: String) => AttributeValue.StringSeqValue(seq.asInstanceOf[Seq[String]]) | ||
| case Some(_: Long) => AttributeValue.LongSeqValue(seq.asInstanceOf[Seq[Long]]) | ||
| case Some(_: Double) => AttributeValue.DoubleSeqValue(seq.asInstanceOf[Seq[Double]]) | ||
| case Some(_: Boolean) => AttributeValue.BooleanSeqValue(seq.asInstanceOf[Seq[Boolean]]) | ||
| case _ => AttributeValue.StringSeqValue(Seq.empty) |
Comment on lines
+96
to
+100
| parentSpanContext = span.toSpanData.parentSpanContext, | ||
| startTimeNanos = span.toSpanData.startTimeNanos, | ||
| initialAttributes = span.toSpanData.attributes, | ||
| initialLinks = span.toSpanData.links, | ||
| resource = resource, |
Comment on lines
+101
to
+105
| val cb = new ObservableCallback { | ||
| def record(value: Double, attributes: Attributes): Unit = { | ||
| measurements.add(SumDataPoint(attributes, 0L, now, value.toLong)) | ||
| () | ||
| } |
Comment on lines
+112
to
+116
| ) | ||
| } else { | ||
| val delayMs = math.min(retryBaseMillis * (1L << attempt), 30000L) | ||
| try Thread.sleep(delayMs) | ||
| catch { case _: InterruptedException => Thread.currentThread().interrupt() } |
- Delete OtelSdk.scala, OtelSdkBuilder, OtelExample.scala (anti-blocks pattern) - Refactor PlatformExecutor from singleton to class with create() factory - Add macro-based log object with GlobalLogState for zero-cost logging - Scala 3: inline + scala.quoted macros - Scala 2: blackbox.Context macros - Captures file, class, method, line at compile time - Level check before argument evaluation - Fix Oracle review issues: - OtlpJsonEncoder: surrogate pair escaping, log flags field emission - TracerProvider/LoggerProvider: null -> Option for contextStorage - BatchProcessor: accepts ScheduledExecutorService, retry delay capped at 30s - BranchCoverageSpec: fix span.isRecording ZIO test laziness - Coverage: 93.83% stmt, 90.21% branch (exceeds 80/70 thresholds)
… cross-compile JVM+JS
- LogEnrichment[A] type class with compile-time macro summoning
- Scala 3: inline varargs + Varargs extractor + Expr.summon (zero allocation)
- Scala 2: blackbox.Context + c.inferImplicitValue
- Built-in instances: String, Throwable, tuple attrs, Attributes, Severity
- Zero cost: all enrichment code inside level guard
- API: log.info("msg", "key" -> 42L, exception)
- Hierarchical per-class log levels via prefix-matching Map in GlobalLogState
- setLevel/clearLevel/clearAllLevels with thread-safe CAS
- Most-specific prefix wins
- log.annotated for scoped contextual annotations
- ThreadLocal-backed on JVM, global var on JS
- Scoped-only API, impossible to leak
- Cross-compiled otel module for JVM + JS
- Converted from project to crossProject(JSPlatform, JVMPlatform)
- JS ContextStorage + LogAnnotations implementations
- SpanId/TraceId: ThreadLocalRandom -> scala.util.Random for cross-platform
- 625 JVM tests + 448 JS tests pass
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Custom OpenTelemetry implementation for zio-blocks — zero Java SDK dependency, implementing the OTel standard from scratch in blocks style.
tracer.span("op") { span => ... }), automatic parent-child linking via ContextStorage, AlwaysOn/AlwaysOff/ParentBased samplingKey Design Decisions
$[Span]wrappercontext.jvm+chunk.jvmClass.forNamereflection — single JAR, no Multi-Release JARFiles
otel/src/main/scala/zio/blocks/otel/otel/src/test/scala/zio/blocks/otel/build.sbtupdated with otel project definition + aliasesTesting