packages feed

freckle-otel 0.0.0.3 → 0.1.0.0

raw patch · 6 files changed

+100/−51 lines, 6 filesdep ~Blammodep ~aesondep ~basePVP ok

version bump matches the API change (PVP)

Dependency ranges changed: Blammo, aeson, base, bytestring, exceptions, faktory, hs-opentelemetry-api, hs-opentelemetry-sdk, hspec, hspec-core, http-client, http-types, lens, mtl, text, unordered-containers

API changes (from Hackage documentation)

Files

CHANGELOG.md view
@@ -1,4 +1,24 @@-## [_Unreleased_](https://github.com/freckle/freckle-otel/compare/v0.0.0.3...main)+## [_Unreleased_](https://github.com/freckle/freckle-otel/compare/v0.1.0.0...main)++## [v0.1.0.0](https://github.com/freckle/freckle-otel/compare/v0.0.0.3...v0.1.0.0)++Drops support for GHC 9.2 and GHC 9.4. `hs-opentelemetry-sdk`'s OTLP exporter now depends on a+`tls`/`crypton` stack too recent to satisfy against those two GHC versions' package sets. GHC 9.6+is now the oldest supported version, which also drops support for `base` 4.16 and 4.17.++Require `hs-opentelemetry-api` and `hs-opentelemetry-sdk` at `1.0.0.0` or later. A few behavior+changes from that upgrade are visible through this package's own functions:++- `withTracerProvider`'s shutdown now applies a default 5 second timeout instead of waiting+  indefinitely+- `inSpan`, and so `getCurrentSpanContext`, `getCurrentTraceId`, `addCurrentSpanAttributes`, and+  `withTraceContext`, no longer see the current span when the `TracerProvider` has no+  `SpanProcessor` configured (e.g. `OTEL_TRACES_EXPORTER=none`)+- `extractContext`, `injectContext`, and `processWithContext` keep propagating trace context via+  headers even when `OTEL_SDK_DISABLED=true`, where they previously became no-ops+- the `traceparent` header `injectContext`/`processWithContext` write for a sampled root span now+  has its trailing flags byte set to `03` (sampled, plus the new W3C Trace Context "random trace+  ID" bit), where it was previously `00`  ## [v0.0.0.3](https://github.com/freckle/freckle-otel/compare/v0.0.0.2...v0.0.0.3) 
freckle-otel.cabal view
@@ -1,6 +1,6 @@ cabal-version:      1.18 name:               freckle-otel-version:            0.0.0.3+version:            0.1.0.0 license:            MIT license-file:       LICENSE maintainer:         Freckle Education@@ -45,23 +45,23 @@         -Wno-safe -Wno-unsafe      build-depends:-        Blammo >=2.1.0.0,-        aeson >=2.0.3.0,-        base >=4.16.4.0 && <5,-        bytestring >=0.11.4.0,+        Blammo >=2.1.1.0,+        aeson >=2.1.2.1,+        base >=4.18.2.1 && <5,+        bytestring >=0.11.5.3,         case-insensitive >=1.2.1.0,         errors >=2.3.0,-        exceptions >=0.10.4,-        faktory >=1.1.2.4,-        hs-opentelemetry-api >=0.1.0.0,-        hs-opentelemetry-sdk >=0.0.3.6,-        http-client >=0.7.13.1,+        exceptions >=0.10.7,+        faktory >=1.1.3.0,+        hs-opentelemetry-api >=1.0.0.0,+        hs-opentelemetry-sdk >=1.0.0.0,+        http-client >=0.7.17,         http-conduit >=2.3.5,-        http-types >=0.12.3,-        lens >=5.1.1,-        text >=1.2.5.0,+        http-types >=0.12.4,+        lens >=5.2.3,+        text >=2.0.2,         unliftio >=0.2.25.0,-        unordered-containers >=0.2.19.1+        unordered-containers >=0.2.20      if impl(ghc >=9.8)         ghc-options:@@ -91,20 +91,20 @@         -Wno-safe -Wno-unsafe -threaded -rtsopts -with-rtsopts=-N      build-depends:-        Blammo >=2.1.0.0,-        base >=4.16.4.0 && <5,-        exceptions >=0.10.4,+        Blammo >=2.1.1.0,+        base >=4.18.2.1 && <5,+        exceptions >=0.10.7,         freckle-env >=0.0.1.2,         freckle-otel,-        hs-opentelemetry-api >=0.1.0.0,-        hs-opentelemetry-sdk >=0.0.3.6,-        hspec >=2.9.7,-        hspec-core >=2.9.7,+        hs-opentelemetry-api >=1.0.0.0,+        hs-opentelemetry-sdk >=1.0.0.0,+        hspec >=2.11.10,+        hspec-core >=2.11.10,         hspec-expectations-lifted >=0.10.0,-        http-types >=0.12.3,-        lens >=5.1.1,-        mtl >=2.2.2,-        text >=1.2.5.0,+        http-types >=0.12.4,+        lens >=5.2.3,+        mtl >=2.3.1,+        text >=2.0.2,         unliftio >=0.2.25.0      if impl(ghc >=9.8)
library/Freckle/App/OpenTelemetry.hs view
@@ -19,11 +19,8 @@ -- You may need to do this even if you don't plan to manually trace things, in -- order to satisfy the 'MonadTracer' constraint required by functions like -- 'runDB'. If you don't need this feature, and don't plan on running an--- otel-collector, set @OTEL_TRACES_EXPORTER=none@ in the environment, which--- makes all tracing a no-op.------ In the future, it should be possible to use @OTEL_SDK_DISABLED@ for the same--- purpose. See <https://github.com/iand675/hs-opentelemetry/issues/60>.+-- otel-collector, set @OTEL_SDK_DISABLED=true@ in the environment, to+-- disable any actual tracing. module Freckle.App.OpenTelemetry   ( HasTracer (..)   , Tracer@@ -76,7 +73,7 @@ import Data.Text.Encoding.Error qualified as T import OpenTelemetry.Context (lookupSpan) import OpenTelemetry.Context.ThreadLocal (getContext)-import OpenTelemetry.Trace hiding (inSpan)+import OpenTelemetry.Trace hiding (inSpan, withTracerProvider) import OpenTelemetry.Trace.Core (getSpanContext) import OpenTelemetry.Trace.Core qualified as Trace (SpanContext (..)) import OpenTelemetry.Trace.Id@@ -127,7 +124,7 @@ withTracerProvider =   bracket     (liftIO initializeGlobalTracerProvider)-    (liftIO . shutdownTracerProvider)+    (void . liftIO . flip shutdownTracerProvider Nothing)  getCurrentTraceId :: MonadIO m => m (Maybe TraceId) getCurrentTraceId = fmap Trace.traceId <$> getCurrentSpanContext
library/Freckle/App/OpenTelemetry/Context.hs view
@@ -38,7 +38,14 @@ import Network.HTTP.Types.Header (Header) import OpenTelemetry.Context (Context) import OpenTelemetry.Context.ThreadLocal (attachContext, getContext)-import OpenTelemetry.Propagator (Propagator, extract, inject)+import OpenTelemetry.Propagator+  ( Propagator+  , TextMap+  , extract+  , inject+  , textMapFromList+  , textMapToList+  ) import OpenTelemetry.Trace.Core   ( getTracerProviderPropagators   , getTracerTracerProvider@@ -89,7 +96,7 @@ extractContext a = do   context <- getContext   propagator <- getPropagator-  updatedContext <- extract propagator (a ^. headersL) context+  updatedContext <- extract propagator (headersToTextMap $ a ^. headersL) context   void $ attachContext updatedContext  -- | Inject our trace context into the given item's headers@@ -98,12 +105,20 @@ injectContext a = do   context <- getContext   propagator <- getPropagator-  headers <- inject propagator context $ a ^. headersL+  headers <-+    textMapToHeaders+      <$> inject propagator context (headersToTextMap $ a ^. headersL)   pure $ a & headersL .~ headers -getPropagator :: MonadTracer m => m (Propagator Context [Header] [Header])+getPropagator :: MonadTracer m => m (Propagator Context TextMap TextMap) getPropagator =   getTracerProviderPropagators . getTracerTracerProvider <$> getTracer++headersToTextMap :: [Header] -> TextMap+headersToTextMap = textMapFromList . map decode++textMapToHeaders :: TextMap -> [Header]+textMapToHeaders = map encode . textMapToList  -- | Process an item (a request, a Job, etc) in a top-level span and context processWithContext
package.yaml view
@@ -1,5 +1,5 @@ name: freckle-otel-version: 0.0.0.3+version: 0.1.0.0 maintainer: Freckle Education category: OpenTelemetry, Telemetry, Monitoring, Observability, Metrics github: freckle/freckle-otel
tests/Freckle/App/OpenTelemetry/ContextSpec.hs view
@@ -9,6 +9,7 @@ import Blammo.Logging.Logger (Logger, newTestLogger) import Blammo.Logging.Setup (HasLogger (..)) import Control.Lens (lens)+import Control.Monad (void) import Control.Monad.IO.Class (MonadIO) import Data.List qualified as List import Data.Text (Text)@@ -18,6 +19,8 @@ import Freckle.App.OpenTelemetry.Context import GHC.Stack (HasCallStack) import Network.HTTP.Types.Header (Header)+import OpenTelemetry.Exporter.Span (ExportResult (..), SpanExporter (..))+import OpenTelemetry.Registry (registerSpanExporterFactoryIfAbsent) import OpenTelemetry.Trace.Core qualified as Trace import Test.Hspec (Spec, describe, it) import Test.Hspec.Expectations.Lifted@@ -42,26 +45,42 @@ loadApp f = do   appLogger <- newTestLogger defaultLogSettings +  -- A TracerProvider with no SpanProcessor never attaches its spans to+  -- context, so getCurrentSpanContext wouldn't see them; register a no-op+  -- exporter so one exists without actually exporting anywhere+  void+    $ registerSpanExporterFactoryIfAbsent "freckle-otel-test-noop"+    $ pure noopSpanExporter+   withTracerProvider $ \tracerProvider -> do     let appTracer = makeTracer tracerProvider "app" tracerOptions     f App {..} +noopSpanExporter :: SpanExporter+noopSpanExporter =+  SpanExporter+    { spanExporterExport = const $ pure Success+    , spanExporterShutdown = pure Trace.ShutdownSuccess+    , spanExporterForceFlush = pure Trace.FlushSuccess+    }+ spec :: Spec spec = withApp loadApp $ do   describe "injectContext" $ do     it "sets request headers from existing context" $ appExample @App $ do       inSpan "example" defaultSpanArguments $ do         spanContext <- assertCurrentSpanContext+        headers <- injectContext ([] :: [Header]) -        let expectedTraceParent =-              toTraceParent-                (traceIdToHex $ Trace.traceId spanContext)-                (spanIdToHex $ Trace.spanId spanContext)+        let headerTraceParent = do+              bs <- List.lookup "traceparent" headers+              fromTraceParent $ T.decodeUtf8 bs -        injectContext ([] :: [Header])-          `shouldReturn` [ ("traceparent", T.encodeUtf8 expectedTraceParent)-                         , ("tracestate", "")-                         ]+        fmap fst headerTraceParent+          `shouldBe` Just (traceIdToHex $ Trace.traceId spanContext)+        fmap snd headerTraceParent+          `shouldBe` Just (spanIdToHex $ Trace.spanId spanContext)+        List.lookup "tracestate" headers `shouldBe` Just ""    describe "extractContext" $ do     it "sets the context from the headers" $ appExample @App $ do@@ -163,11 +182,9 @@ toTraceParent traceId spanId = "00-" <> traceId <> "-" <> spanId <> "-00"  fromTraceParent :: Text -> Maybe (Text, Text)-fromTraceParent a = do-  b <- T.stripPrefix "00-" a-  c <- T.stripSuffix "-00" b-  [traceId, spanId] <- Just $ T.splitOn "-" c-  pure (traceId, spanId)+fromTraceParent a = case T.splitOn "-" a of+  [_version, traceId, spanId, _flags] -> Just (traceId, spanId)+  _ -> Nothing  expectationFailure :: (HasCallStack, MonadIO m) => String -> m a expectationFailure msg = Hspec.expectationFailure msg >> error "unreachable"