diff --git a/src/exporter/otlp/proto/http/Project.toml b/src/exporter/otlp/proto/http/Project.toml index 9816b34..477587d 100644 --- a/src/exporter/otlp/proto/http/Project.toml +++ b/src/exporter/otlp/proto/http/Project.toml @@ -1,7 +1,7 @@ name = "OpenTelemetryExporterOtlpProtoHttp" uuid = "f175482f-0544-4037-b362-361efbf21c04" authors = ["Jun Tian "] -version = "0.1.6" +version = "0.1.7" [deps] HTTP = "cd3eb016-35fb-5094-929b-558a96fad6f3" @@ -11,7 +11,7 @@ OpenTelemetrySDK = "f5929ecf-be04-446c-b2f2-494e1fe70ee4" ProtoBuf = "3349acd9-ac6a-5e09-bcdb-63829b23a429" [compat] -HTTP = "1" +HTTP = "1, 2" OpenTelemetryAPI = "0.4,0.5" OpenTelemetryProto = "0.19,0.20" OpenTelemetrySDK = "0.3,0.4" diff --git a/src/exporter/otlp/proto/http/src/OpenTelemetryExporterOtlpProtoHttp.jl b/src/exporter/otlp/proto/http/src/OpenTelemetryExporterOtlpProtoHttp.jl index bacfaac..5308dbd 100644 --- a/src/exporter/otlp/proto/http/src/OpenTelemetryExporterOtlpProtoHttp.jl +++ b/src/exporter/otlp/proto/http/src/OpenTelemetryExporterOtlpProtoHttp.jl @@ -20,6 +20,21 @@ import OpenTelemetryProto.opentelemetry.proto.metrics.v1 as METRICS import OpenTelemetryProto.opentelemetry.proto.common.v1 as COMMON import OpenTelemetryProto.opentelemetry.proto.resource.v1 as RESOURCE +# HTTP.jl 2.0 renamed the request-wide deadline keyword: `readtimeout` (HTTP 1.x) +# became a deprecated alias mapping to the inactivity-based `read_idle_timeout`, +# while overall request deadlines now use `request_timeout`. Detect the major +# version once at load time and pick the right keyword. +# +# Primary signal is the package version. `pkgversion(::Module)` exists since +# Julia 1.9 but may return `nothing` (e.g. when a module wasn't loaded from a +# versioned package), so we fall back to API feature detection: the `HTTP.Servers` +# submodule exists throughout HTTP 1.x and was removed in 2.0, making it a +# reliable discriminator that also covers Julia < 1.9 (where only HTTP 1 can +# resolve, since HTTP 2 requires Julia >= 1.10). +const _HTTP_V2 = let v = isdefined(Base, :pkgversion) ? Base.pkgversion(HTTP) : nothing + v === nothing ? !isdefined(HTTP, :Servers) : v >= v"2" +end + struct OtlpHttpExporter{Req,Resp} <: SDK.AbstractExporter url::String headers::Vector{Pair{String,String}} @@ -76,14 +91,18 @@ function SDK.export!(x::OtlpHttpExporter{Req,Resp}, batch::Union{AbstractVector, encode(e, convert(Req, batch)) seekstart(io) + # `retry` / `retry_non_idempotent` remain valid keywords in both HTTP 1.x + # and 2.x; only the timeout keyword changed (see `_HTTP_V2` above). + timeout_kw = _HTTP_V2 ? (; request_timeout = x.timeout) : (; readtimeout = x.timeout) + res = API.with_context(; API.SUPPRESS_INSTRUMENTATION_KEY => true) do HTTP.post( - x.url, - x.headers; - body = io, - readtimeout=x.timeout, - retry=true, - retry_non_idempotent=true + x.url, + x.headers; + body = io, + retry = true, + retry_non_idempotent = true, + timeout_kw..., ) end diff --git a/src/exporter/prometheus/Project.toml b/src/exporter/prometheus/Project.toml index 257d7e9..c9498f8 100644 --- a/src/exporter/prometheus/Project.toml +++ b/src/exporter/prometheus/Project.toml @@ -1,7 +1,7 @@ name = "OpenTelemetryExporterPrometheus" uuid = "34e26579-e93c-4b5e-ba07-7afb633408c2" authors = ["Jun Tian "] -version = "0.3.1" +version = "0.3.2" [deps] Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" @@ -10,7 +10,7 @@ OpenTelemetrySDK = "f5929ecf-be04-446c-b2f2-494e1fe70ee4" URIs = "5c2747f8-b7ea-4ff2-ba2e-563bfd36b1d4" [compat] -HTTP = "1" +HTTP = "1, 2" OpenTelemetrySDK = "0.4" URIs = "1" julia = "1" diff --git a/src/exporter/prometheus/src/OpenTelemetryExporterPrometheus.jl b/src/exporter/prometheus/src/OpenTelemetryExporterPrometheus.jl index dae2f09..17eae63 100644 --- a/src/exporter/prometheus/src/OpenTelemetryExporterPrometheus.jl +++ b/src/exporter/prometheus/src/OpenTelemetryExporterPrometheus.jl @@ -5,8 +5,11 @@ export PrometheusExporter using OpenTelemetrySDK using HTTP +# A request handler returning an `HTTP.Response`. This works identically across +# HTTP.jl 1.x and 2.x. (HTTP 2.0 dropped the `stream = true` server mode and the +# `setstatus`/`setheader`/`startwrite` streaming helpers in favor of returning a +# `Response`; buffering the body here keeps a single code path for both.) function handler( - io, provider::Ref{MeterProvider}, resource_to_telemetry_conversion, with_timestamp, @@ -14,11 +17,9 @@ function handler( for ins in provider[].async_instruments ins() end - HTTP.setstatus(io, 200) - HTTP.setheader(io, "Content-Type" => "text/plain") - HTTP.startwrite(io) + io = IOBuffer() text_based_format(io, provider[], resource_to_telemetry_conversion; with_timestamp) - nothing + HTTP.Response(200, ["Content-Type" => "text/plain"]; body = take!(io)) end """ @@ -40,7 +41,9 @@ r = MetricReader(PrometheusExporter()) Note that `PrometheusExporter` is a pull based exporter. There's no need to execute `r()` to update the metrics. """ mutable struct PrometheusExporter <: OpenTelemetrySDK.AbstractExporter - server::HTTP.Servers.Server + # Untyped: the running-server handle type differs between HTTP.jl versions + # (`HTTP.Servers.Server` on 1.x, `HTTP.Server` on 2.x). + server::Any provider::Ref{MeterProvider} function PrometheusExporter(; host = OTEL_EXPORTER_PROMETHEUS_HOST(), @@ -57,9 +60,9 @@ mutable struct PrometheusExporter <: OpenTelemetrySDK.AbstractExporter router, "GET", path, - io -> handler(io, provider, resource_to_telemetry_conversion, with_timestamp), + _ -> handler(provider, resource_to_telemetry_conversion, with_timestamp), ) - server = HTTP.serve!(router, host, port; stream = true, kw...) + server = HTTP.serve!(router, host, port; kw...) new(server, provider) end