diff --git a/cabal.project b/cabal.project index 55af858a..bc1404ca 100644 --- a/cabal.project +++ b/cabal.project @@ -13,6 +13,7 @@ packages: , instrumentation/conduit , instrumentation/grpc-haskell , instrumentation/hedis + , instrumentation/herp-logger-datadog , instrumentation/hspec , instrumentation/http-client , instrumentation/persistent @@ -25,6 +26,7 @@ packages: , examples/yesod-minimal , examples/yesod-subsite , utils/exceptions + , vendors/datadog -- https://github.com/vincenthz/hs-memory/pull/93 source-repository-package @@ -34,11 +36,16 @@ source-repository-package source-repository-package type: git - location: http://github.com/awakesecurity/gRPC-haskell + location: https://github.com/awakesecurity/gRPC-haskell tag: 0b37ef53702ca315526fbd1643edb8880517ad62 subdir: . core -- HEAD of master at 2023-06-09 +source-repository-package + type: git + location: https://github.com/herp-inc/herp-logger + tag: v0.3 + allow-newer: http-api-data:base , postgresql-simple:base diff --git a/hie.yaml b/hie.yaml index 44e6e69a..e240c010 100644 --- a/hie.yaml +++ b/hie.yaml @@ -92,6 +92,9 @@ cradle: - path: "instrumentation/hedis/gen" component: "lib:hs-opentelemetry-instrumentation-hedis" + - path: "instrumentation/herp-logger-datadog/src" + component: "lib:hs-opentelemetry-instrumentation-herp-logger-datadog" + - path: "instrumentation/hspec/src" component: "lib:hs-opentelemetry-instrumentation-hspec" @@ -184,3 +187,9 @@ cradle: - path: "utils/exceptions/test" component: "hs-opentelemetry-utils-exceptions:test:exceptions-test" + + - path: "vendors/datadog" + component: "lib:hs-opentelemetry-vendor-datadog" + + - path: "vendors/datadog/test/spec" + component: "hs-opentelemetry-vendors-datadog:test:spec" diff --git a/instrumentation/herp-logger-datadog/hs-opentelemetry-instrumentation-herp-loger-datadog.cabal b/instrumentation/herp-logger-datadog/hs-opentelemetry-instrumentation-herp-loger-datadog.cabal new file mode 100644 index 00000000..8bf82558 --- /dev/null +++ b/instrumentation/herp-logger-datadog/hs-opentelemetry-instrumentation-herp-loger-datadog.cabal @@ -0,0 +1,54 @@ +cabal-version: 2.4 + +name: hs-opentelemetry-instrumentation-herp-loger-datadog +version: 0.0.0.0 +author: Kazuki Okamoto (岡本和樹) +maintainer: kazuki.okamoto@herp.co.jp + +common common + build-depends: base >= 4 && < 5 + ghc-options: -Wall + if impl(ghc >= 8.0) + ghc-options: -Wcompat + default-language: Haskell2010 + +library + import: common + hs-source-dirs: src + exposed-modules: OpenTelemetry.Instrumentation.Herp.Logger.Datadog + build-depends: hs-opentelemetry-api, + hs-opentelemetry-vendor-datadog, + aeson, + herp-logger, + monad-logger, + mtl, + text, + ghc-options: -Wcompat + -Wno-name-shadowing + if impl(ghc >= 6.4) + ghc-options: -Wincomplete-record-updates + if impl(ghc >= 6.8) + ghc-options: -Wmonomorphism-restriction + if impl(ghc >= 7.0) + ghc-options: -Wmissing-import-lists + if impl(ghc >= 7.2) + ghc-options: -Wincomplete-uni-patterns + -Widentities + if impl(ghc >= 8.0) + ghc-options: -Wmissing-exported-signatures + -Wredundant-constraints + if impl(ghc >= 8.2) + ghc-options: -Wmissing-home-modules + if impl(ghc >= 8.4) + ghc-options: -Wmissing-export-lists + -Wpartial-fields + if impl(ghc >= 8.8) + ghc-options: -Wmissing-deriving-strategies + if impl(ghc >= 8.10) + ghc-options: -Wunused-packages + if impl(ghc >= 9.0) + ghc-options: -Winvalid-haddock + if impl(ghc >= 9.2) + ghc-options: -Wmissing-kind-signatures + -Woperator-whitespace + -Wredundant-bang-patterns diff --git a/instrumentation/herp-logger-datadog/src/OpenTelemetry/Instrumentation/Herp/Logger/Datadog.hs b/instrumentation/herp-logger-datadog/src/OpenTelemetry/Instrumentation/Herp/Logger/Datadog.hs new file mode 100644 index 00000000..f06be2cb --- /dev/null +++ b/instrumentation/herp-logger-datadog/src/OpenTelemetry/Instrumentation/Herp/Logger/Datadog.hs @@ -0,0 +1,180 @@ +{-# LANGUAGE NamedFieldPuns #-} +{-# LANGUAGE OverloadedLabels #-} +{-# LANGUAGE OverloadedLists #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE TupleSections #-} + +-- | This is herp-logger with connections of OpenTelemetry Traces and Logs. +-- +-- Datadog functionality about connections of Traces and Logs is described in +-- . +-- +-- This logger requires 'Otel.Tracer' to retrieve OpenTelemetry context additionally. +module OpenTelemetry.Instrumentation.Herp.Logger.Datadog ( + (Orig..=), + Orig.Logger (..), + Orig.HasLogger (..), + Orig.LogLevel (..), + Orig.LoggerConfig (..), + Orig.newLogger, + Orig.withLogger, + Orig.defaultLoggerConfig, + logM, + logOtherM, + logDebugM, + logInfoM, + logNoticeM, + logWarnM, + logErrorM, + logCritM, + logAlertM, + logEmergM, + logIO, + Orig.urgentLog, + Orig.flush, + + -- * Payload + Orig.Payload, + Orig.level, + Orig.message, + Orig.object, + Orig.messageString, + Orig.messageShow, + Orig.messageException, + + -- * monad-logger + runLoggingT, + toLoggerIO, +) where + +import Control.Applicative (Alternative ((<|>))) +import Control.Monad (void) +import Control.Monad.IO.Class (MonadIO) +import qualified Control.Monad.Logger as ML +import Control.Monad.Reader.Class (MonadReader (ask)) +import qualified Data.Aeson.KeyMap as Aeson +import qualified Data.Aeson.Types as Aeson +import Data.Maybe (maybeToList) +import Data.Text (Text) +import qualified Data.Text as Text +import qualified Data.Text.Encoding as Text +import Herp.Logger ((.=)) +import qualified Herp.Logger as Orig +import qualified Herp.Logger.LogLevel as Orig +import qualified Herp.Logger.Payload as Orig +import qualified OpenTelemetry.Attributes as Otel +import qualified OpenTelemetry.Context as Otel +import qualified OpenTelemetry.Context.ThreadLocal as Otel +import qualified OpenTelemetry.Resource as Otel +import qualified OpenTelemetry.Trace.Core as Otel +import qualified OpenTelemetry.Vendor.Datadog as Datadog + + +logIO :: MonadIO m => Otel.Tracer -> Orig.Logger -> Orig.Payload -> m () +logIO tracer logger payload = do + context <- Otel.getContext + payload' <- datadogPayload (Otel.getTracerTracerProvider tracer) $ Otel.lookupSpan context + Orig.logIO logger (payload' <> payload) +{-# INLINE logIO #-} + + +logM :: (MonadIO m, MonadReader r m, Orig.HasLogger r, Otel.HasTracer r) => Orig.Payload -> m () +logM payload = do + r <- ask + void $ flip Otel.tracerL r $ \tracer -> do + logIO tracer (Orig.toLogger r) payload + pure tracer +{-# INLINE logM #-} + + +logOtherM :: (MonadIO m, MonadReader r m, Orig.HasLogger r, Otel.HasTracer r) => Orig.LogLevel -> Orig.Payload -> m () +logOtherM logLevel payload = logM $ Orig.level logLevel <> payload + + +logDebugM :: (MonadIO m, MonadReader r m, Orig.HasLogger r, Otel.HasTracer r) => Orig.Payload -> m () +logDebugM = logOtherM Orig.Debug + + +logInfoM :: (MonadIO m, MonadReader r m, Orig.HasLogger r, Otel.HasTracer r) => Orig.Payload -> m () +logInfoM = logOtherM Orig.Informational + + +logNoticeM :: (MonadIO m, MonadReader r m, Orig.HasLogger r, Otel.HasTracer r) => Orig.Payload -> m () +logNoticeM = logOtherM Orig.Notice + + +logWarnM :: (MonadIO m, MonadReader r m, Orig.HasLogger r, Otel.HasTracer r) => Orig.Payload -> m () +logWarnM = logOtherM Orig.Warning + + +logErrorM :: (MonadIO m, MonadReader r m, Orig.HasLogger r, Otel.HasTracer r) => Orig.Payload -> m () +logErrorM = logOtherM Orig.Error + + +logCritM :: (MonadIO m, MonadReader r m, Orig.HasLogger r, Otel.HasTracer r) => Orig.Payload -> m () +logCritM = logOtherM Orig.Critical + + +logAlertM :: (MonadIO m, MonadReader r m, Orig.HasLogger r, Otel.HasTracer r) => Orig.Payload -> m () +logAlertM = logOtherM Orig.Alert + + +logEmergM :: (MonadIO m, MonadReader r m, Orig.HasLogger r, Otel.HasTracer r) => Orig.Payload -> m () +logEmergM = logOtherM Orig.Emergency + + +runLoggingT :: Otel.Tracer -> Orig.Logger -> ML.LoggingT m a -> m a +runLoggingT tracer logger (ML.LoggingT run) = run $ toLoggerIO tracer logger + + +toLoggerIO :: Otel.Tracer -> Orig.Logger -> ML.Loc -> ML.LogSource -> ML.LogLevel -> ML.LogStr -> IO () +toLoggerIO tracer logger loc logSrc lv logStr = do + let msg = Text.decodeUtf8 $ ML.fromLogStr $ ML.defaultLogStr loc logSrc lv logStr + logIO + tracer + logger + [ Orig.message msg + , case Orig.convertLogLevel lv of + Right x -> Orig.level x + Left other -> [#warn, "level" .= other] + ] + + +datadogPayload :: MonadIO m => Otel.TracerProvider -> Maybe Otel.Span -> m Orig.Payload +datadogPayload tracerProvider maybeSpan = do + (maybeSpanId, maybeTraceId) <- + case maybeSpan of + Nothing -> pure (Nothing, Nothing) + Just span -> do + Otel.SpanContext {Otel.spanId, Otel.traceId} <- Otel.getSpanContext span + pure + ( Just $ Text.pack $ show $ Datadog.convertOpenTelemetrySpanIdToDatadogSpanId spanId + , Just $ Text.pack $ show $ Datadog.convertOpenTelemetryTraceIdToDatadogTraceId traceId + ) + let + attributes = Otel.getMaterializedResourcesAttributes $ Otel.getTracerProviderResources tracerProvider + maybeEnv = attributeAsText =<< Otel.lookupAttribute attributes Datadog.envKey + maybeService = + attributeAsText + =<< ( Otel.lookupAttribute attributes Datadog.serviceKey + <|> + -- "service.name" is the same key in the OpenTelemetry.Resource.Service module + Otel.lookupAttribute attributes "service.name" + ) + maybeVersion = attributeAsText =<< Otel.lookupAttribute attributes Datadog.versionKey + pure $ + (\payloadObject -> mempty {Orig.payloadObject}) $ + Aeson.fromList $ + mconcat $ + maybeToList + <$> [ ("span_id",) . Aeson.String <$> maybeSpanId + , ("trace_id",) . Aeson.String <$> maybeTraceId + , ("dd.env",) . Aeson.String <$> maybeEnv + , ("dd.service",) . Aeson.String <$> maybeService + , ("dd.version",) . Aeson.String <$> maybeVersion + ] + + +attributeAsText :: Otel.Attribute -> Maybe Text +attributeAsText (Otel.AttributeValue (Otel.TextAttribute a)) = Just a +attributeAsText _ = Nothing diff --git a/propagators/datadog/hs-opentelemetry-propagator-datadog.cabal b/propagators/datadog/hs-opentelemetry-propagator-datadog.cabal index 911e92eb..e427744d 100644 --- a/propagators/datadog/hs-opentelemetry-propagator-datadog.cabal +++ b/propagators/datadog/hs-opentelemetry-propagator-datadog.cabal @@ -20,6 +20,7 @@ library build-depends: bytestring, hs-opentelemetry-api, hs-opentelemetry-sdk, + hs-opentelemetry-vendor-datadog, http-types, primitive, text @@ -59,8 +60,7 @@ test-suite spec main-is: Spec.hs hs-source-dirs: test/spec old-src - other-modules: OpenTelemetry.Propagator.DatadogSpec - OpenTelemetry.Propagator.Datadog.InternalSpec + other-modules: OpenTelemetry.Propagator.Datadog.InternalSpec Raw String build-depends: hs-opentelemetry-propagator-datadog, diff --git a/propagators/datadog/src/OpenTelemetry/Propagator/Datadog.hs b/propagators/datadog/src/OpenTelemetry/Propagator/Datadog.hs index 9aaa2ca0..60a91c2f 100644 --- a/propagators/datadog/src/OpenTelemetry/Propagator/Datadog.hs +++ b/propagators/datadog/src/OpenTelemetry/Propagator/Datadog.hs @@ -4,16 +4,11 @@ module OpenTelemetry.Propagator.Datadog ( datadogTraceContextPropagator, - convertOpenTelemetrySpanIdToDatadogSpanId, - convertOpenTelemetryTraceIdToDatadogTraceId, ) where import qualified Data.ByteString.Char8 as BC -import qualified Data.ByteString.Short.Internal as SBI -import Data.Primitive (ByteArray (ByteArray)) import Data.String (IsString) import qualified Data.Text as T -import Data.Word (Word64) import Network.HTTP.Types ( RequestHeaders, ResponseHeaders, @@ -30,7 +25,6 @@ import OpenTelemetry.Internal.Trace.Id ( ) import OpenTelemetry.Propagator (Propagator (Propagator, extractor, injector, propagatorNames)) import OpenTelemetry.Propagator.Datadog.Internal ( - indexByteArrayNbo, newHeaderFromSpanId, newHeaderFromTraceId, newSpanIdFromHeader, @@ -45,9 +39,6 @@ import OpenTelemetry.Trace.TraceState (TraceState (TraceState)) import qualified OpenTelemetry.Trace.TraceState as TS --- Reference: bi-directional conversion of IDs of Open Telemetry and ones of Datadog --- - English: https://docs.datadoghq.com/tracing/other_telemetry/connect_logs_and_traces/opentelemetry/ --- - Japanese: https://docs.datadoghq.com/ja/tracing/connect_logs_and_traces/opentelemetry/ datadogTraceContextPropagator :: Propagator Context RequestHeaders ResponseHeaders datadogTraceContextPropagator = Propagator @@ -94,11 +85,3 @@ datadogTraceContextPropagator = traceIdKey = "x-datadog-trace-id" parentIdKey = "x-datadog-parent-id" samplingPriorityKey = "x-datadog-sampling-priority" - - -convertOpenTelemetrySpanIdToDatadogSpanId :: SpanId -> Word64 -convertOpenTelemetrySpanIdToDatadogSpanId (SpanId (SBI.SBS a)) = indexByteArrayNbo (ByteArray a) 0 - - -convertOpenTelemetryTraceIdToDatadogTraceId :: TraceId -> Word64 -convertOpenTelemetryTraceIdToDatadogTraceId (TraceId (SBI.SBS a)) = indexByteArrayNbo (ByteArray a) 1 diff --git a/propagators/datadog/src/OpenTelemetry/Propagator/Datadog/Internal.hs b/propagators/datadog/src/OpenTelemetry/Propagator/Datadog/Internal.hs index 8ffba4cd..3ee1c87b 100644 --- a/propagators/datadog/src/OpenTelemetry/Propagator/Datadog/Internal.hs +++ b/propagators/datadog/src/OpenTelemetry/Propagator/Datadog/Internal.hs @@ -2,26 +2,13 @@ {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE Strict #-} -{- | Conversion of the hs-opentelemetry internal representation of the trace ID and the span ID and the Datadog header representation of them each other. - -+----------+-----------------+----------------+ -| | Trace ID | Span ID | -+----------+-----------------+----------------+ -| Internal | 128-bit integer | 64-bit integer | -+----------+-----------------+----------------+ -| Datadog | ASCII text of | ASCII text of | -| Header | 64-bit integer | 64-bit integer | -+----------+-----------------+----------------+ --} module OpenTelemetry.Propagator.Datadog.Internal ( newTraceIdFromHeader, newSpanIdFromHeader, newHeaderFromTraceId, newHeaderFromSpanId, - indexByteArrayNbo, ) where -import Data.Bits (Bits (shift)) import Data.ByteString (ByteString) import qualified Data.ByteString.Builder as BB import qualified Data.ByteString.Internal as BI @@ -30,11 +17,12 @@ import Data.ByteString.Short (ShortByteString) import qualified Data.ByteString.Short as SB import qualified Data.ByteString.Short.Internal as SBI import qualified Data.Char as C -import Data.Primitive.ByteArray (ByteArray (ByteArray), indexByteArray) +import Data.Primitive.ByteArray (ByteArray (ByteArray)) import Data.Primitive.Ptr (writeOffPtr) import Data.Word (Word64, Word8) import Foreign.ForeignPtr (withForeignPtr) import Foreign.Storable (peekElemOff) +import OpenTelemetry.Vendor.Datadog.Internal (indexByteArrayNbo) import System.IO.Unsafe (unsafeDupablePerformIO) @@ -105,19 +93,6 @@ newHeaderFromSpanId (SBI.SBS ba) = in showWord64BS w64 --- | Read 'ByteArray' to 'Word64' with network-byte-order. -indexByteArrayNbo :: - ByteArray -> - -- | Offset in 'Word64'-size unit - Int -> - Word64 -indexByteArrayNbo ba offset = - loop 0 0 - where - loop 8 acc = acc - loop n acc = loop (n + 1) $ shift acc 8 + word8ToWord64 (indexByteArray ba $ 8 * offset + n) - - showWord64BS :: Word64 -> ByteString showWord64BS v = -- Safe. @@ -141,7 +116,3 @@ showWord64BS v = word8ToAsciiWord8 :: Word8 -> Word8 word8ToAsciiWord8 b = b + fromIntegral (C.ord '0') - - -word8ToWord64 :: Word8 -> Word64 -word8ToWord64 = fromIntegral diff --git a/stack-ghc-8.10.yaml b/stack-ghc-8.10.yaml index a4d12126..46b4d0ce 100644 --- a/stack-ghc-8.10.yaml +++ b/stack-ghc-8.10.yaml @@ -47,6 +47,7 @@ packages: - instrumentation/cloudflare # - instrumentation/grpc-haskell # able to be built with cabal - instrumentation/hedis +# - instrumentation/herp-logger-datadog - instrumentation/http-client - instrumentation/persistent - instrumentation/persistent-mysql @@ -57,6 +58,7 @@ packages: - examples/yesod-minimal - examples/yesod-subsite - utils/exceptions +- vendors/datadog # Dependency packages to be pulled from upstream that are not in the resolver. # These entries can reference officially published versions as well as @@ -74,6 +76,8 @@ extra-deps: - persistent-postgresql-2.13.4.0 - proto-lens-0.7.1.0 - proto-lens-runtime-0.7.0.1 +# - github: herp-inc/herp-logger +# commit: v0.3 # just for testing # - mwc-random-0.14.0.0 # - random-1.1 diff --git a/stack-ghc-8.10.yaml.lock b/stack-ghc-8.10.yaml.lock index 90397a55..0b92d472 100644 --- a/stack-ghc-8.10.yaml.lock +++ b/stack-ghc-8.10.yaml.lock @@ -7,48 +7,48 @@ packages: - completed: hackage: thread-utils-context-0.2.0.0@sha256:7863e568c7a43cd21616342d20484d4c962aaa9710619f104c6fb7ee32273940,1883 pantry-tree: - size: 450 sha256: 605ea068880ad39c96fce0d91db9f2d54553ed43dfc41c37845fade8be2e9568 + size: 450 original: hackage: thread-utils-context-0.2.0.0 - completed: hackage: thread-utils-finalizers-0.1.0.0@sha256:a8435240bfc0ae96c94704d2986699a11a395c496f9a7f2e5f5d729a0b967549,1381 pantry-tree: - size: 400 sha256: 7f708d158d5d0e32ffe77f6375a792ceb6f92e4d8dd8b32fc69e7de962e7e518 + size: 400 original: hackage: thread-utils-finalizers-0.1.0.0 - completed: hackage: persistent-2.13.3.0@sha256:89a4a286ec3739d452f67332a03a392aa57c3e97237b61efcd5b99d50aae9cfc,6762 pantry-tree: - size: 6052 sha256: debd3496e44bf01264de8bc0d3da92991c1550632fe1ef66818392f4c9955323 + size: 6052 original: hackage: persistent-2.13.3.0 - completed: hackage: persistent-postgresql-2.13.4.0@sha256:7fc0ffc4a591c0355c8ad793bc6de08c13321c81a3fb748c9a23448ac88d987a,3686 pantry-tree: - size: 1140 sha256: 78b6907bf9bc82a524251dfeb2cf0d3f8c599427c8ae0b0a1d933158b6909281 + size: 1140 original: hackage: persistent-postgresql-2.13.4.0 - completed: hackage: proto-lens-0.7.1.0@sha256:b151890929e71db5b8c2ad86cd758bcdf1dfcf25f34eb6c9ce19e3d7cd4eae39,2959 pantry-tree: - size: 1857 sha256: 2f1199d04d0588805e06faa0bf9a75898584d76243d4f945acbcc0e93913732e + size: 1857 original: hackage: proto-lens-0.7.1.0 - completed: hackage: proto-lens-runtime-0.7.0.1@sha256:703f327422b2e204f8ea13c5e178edd8ab42ccd01c7a5a89fcb1b37ab474c68a,3038 pantry-tree: - size: 168 sha256: 145cb9a15b73d45b07cb3f9f0716256b2ed9e27ac296268ce100a4f0e477e110 + size: 168 original: hackage: proto-lens-runtime-0.7.0.1 snapshots: - completed: + sha256: 8699812d2b2c1f83d6ad1261de9cf628ed36a1cfc14f19d67188e005e7a3a39d size: 586106 url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/18/20.yaml - sha256: 8699812d2b2c1f83d6ad1261de9cf628ed36a1cfc14f19d67188e005e7a3a39d original: lts-18.20 diff --git a/stack-ghc-9.2.yaml b/stack-ghc-9.2.yaml index 66906db1..4eb2bf93 100644 --- a/stack-ghc-9.2.yaml +++ b/stack-ghc-9.2.yaml @@ -47,6 +47,7 @@ packages: - instrumentation/cloudflare # - instrumentation/grpc-haskell # able to be built with cabal - instrumentation/hedis +# - instrumentation/herp-logger-datadog - instrumentation/http-client - instrumentation/persistent - instrumentation/persistent-mysql @@ -57,6 +58,7 @@ packages: - examples/yesod-minimal - examples/yesod-subsite - utils/exceptions +- vendors/datadog # Dependency packages to be pulled from upstream that are not in the resolver. # These entries can reference officially published versions as well as @@ -72,7 +74,6 @@ extra-deps: - thread-utils-finalizers-0.1.0.0 - proto-lens-0.7.1.1 - proto-lens-runtime-0.7.0.2 - # just for testing # - mwc-random-0.14.0.0 # - random-1.1 diff --git a/stack.yaml b/stack.yaml index 5c183d30..b230a533 100644 --- a/stack.yaml +++ b/stack.yaml @@ -47,6 +47,7 @@ packages: - instrumentation/cloudflare # - instrumentation/grpc-haskell # able to be built with cabal - instrumentation/hedis +# - instrumentation/herp-logger-datadog - instrumentation/hspec - instrumentation/http-client - instrumentation/persistent @@ -58,6 +59,7 @@ packages: - examples/yesod-minimal - examples/yesod-subsite - utils/exceptions +- vendors/datadog # Dependency packages to be pulled from upstream that are not in the resolver. # These entries can reference officially published versions as well as diff --git a/stack.yaml.lock b/stack.yaml.lock index d15e7706..ac8ceb24 100644 --- a/stack.yaml.lock +++ b/stack.yaml.lock @@ -7,41 +7,41 @@ packages: - completed: hackage: hspec-2.10.6@sha256:c90dbcc629e88e5f56021c7dba26a97109a0c441aeece6ead217ee3fc83dcb68,1712 pantry-tree: - size: 583 sha256: e61c983a62c1a72b1fe83aea65f95bba3fcde6f787dc5025090a701894c1b6ff + size: 583 original: hackage: hspec-2.10.6@sha256:c90dbcc629e88e5f56021c7dba26a97109a0c441aeece6ead217ee3fc83dcb68,1712 - completed: hackage: hspec-core-2.10.6@sha256:68a74267974fee22f4bc57b5d353391e8dc943b0d7ffaf5d47dab691765ee772,6659 pantry-tree: - size: 5907 sha256: 2c89341dd4d9ac200c3057e29be34e1c281207e04c44681093dd1e76e3ab46cc + size: 5907 original: hackage: hspec-core-2.10.6@sha256:68a74267974fee22f4bc57b5d353391e8dc943b0d7ffaf5d47dab691765ee772,6659 - completed: hackage: hspec-discover-2.10.6@sha256:df63254c5aa8c5c2b9233b0067728394936b6c9af7e3a5d3d44df78d888dcefd,2167 pantry-tree: - size: 828 sha256: 7cf0a4ca06d993fe934334a4b67ddbc54cfca2b622f795410c1889e6443401eb + size: 828 original: hackage: hspec-discover-2.10.6@sha256:df63254c5aa8c5c2b9233b0067728394936b6c9af7e3a5d3d44df78d888dcefd,2167 - completed: hackage: thread-utils-context-0.2.0.0@sha256:7863e568c7a43cd21616342d20484d4c962aaa9710619f104c6fb7ee32273940,1883 pantry-tree: - size: 450 sha256: 605ea068880ad39c96fce0d91db9f2d54553ed43dfc41c37845fade8be2e9568 + size: 450 original: hackage: thread-utils-context-0.2.0.0@sha256:7863e568c7a43cd21616342d20484d4c962aaa9710619f104c6fb7ee32273940,1883 - completed: hackage: thread-utils-finalizers-0.1.0.0@sha256:a8435240bfc0ae96c94704d2986699a11a395c496f9a7f2e5f5d729a0b967549,1381 pantry-tree: - size: 400 sha256: 7f708d158d5d0e32ffe77f6375a792ceb6f92e4d8dd8b32fc69e7de962e7e518 + size: 400 original: hackage: thread-utils-finalizers-0.1.0.0@sha256:a8435240bfc0ae96c94704d2986699a11a395c496f9a7f2e5f5d729a0b967549,1381 snapshots: - completed: + sha256: e7e57649a12f6178d1158e4b6f1f1885ed56d210ae6174385271cecc9b1ea974 size: 617368 url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/19/2.yaml - sha256: e7e57649a12f6178d1158e4b6f1f1885ed56d210ae6174385271cecc9b1ea974 original: lts-19.2 diff --git a/vendors/datadog/hs-opentelemetry-vendor-datadog.cabal b/vendors/datadog/hs-opentelemetry-vendor-datadog.cabal new file mode 100644 index 00000000..56d298ef --- /dev/null +++ b/vendors/datadog/hs-opentelemetry-vendor-datadog.cabal @@ -0,0 +1,69 @@ +cabal-version: 2.4 + +name: hs-opentelemetry-vendor-datadog +version: 0.0.0.0 +author: Kazuki Okamoto (岡本和樹) +maintainer: kazuki.okamoto@herp.co.jp + +common common + build-depends: base >= 4 && < 5 + ghc-options: -Wall + if impl(ghc >= 8.0) + ghc-options: -Wcompat + default-language: Haskell2010 + +library + import: common + hs-source-dirs: src + exposed-modules: OpenTelemetry.Vendor.Datadog + OpenTelemetry.Vendor.Datadog.Internal + build-depends: hs-opentelemetry-api, + bytestring, + primitive, + text + ghc-options: -Wcompat + -Wno-name-shadowing + if impl(ghc >= 6.4) + ghc-options: -Wincomplete-record-updates + if impl(ghc >= 6.8) + ghc-options: -Wmonomorphism-restriction + if impl(ghc >= 7.0) + ghc-options: -Wmissing-import-lists + if impl(ghc >= 7.2) + ghc-options: -Wincomplete-uni-patterns + -Widentities + if impl(ghc >= 8.0) + ghc-options: -Wmissing-exported-signatures + -Wredundant-constraints + if impl(ghc >= 8.2) + ghc-options: -Wmissing-home-modules + if impl(ghc >= 8.4) + ghc-options: -Wmissing-export-lists + -Wpartial-fields + if impl(ghc >= 8.8) + ghc-options: -Wmissing-deriving-strategies + if impl(ghc >= 8.10) + ghc-options: -Wunused-packages + if impl(ghc >= 9.0) + ghc-options: -Winvalid-haddock + if impl(ghc >= 9.2) + ghc-options: -Wmissing-kind-signatures + -Woperator-whitespace + -Wredundant-bang-patterns + +test-suite spec + import: common + type: exitcode-stdio-1.0 + main-is: Spec.hs + hs-source-dirs: test/spec + old-src + other-modules: OpenTelemetry.Vendor.DatadogSpec + build-depends: hs-opentelemetry-vendor-datadog, + hs-opentelemetry-api, + bytestring, + hspec, + QuickCheck + ghc-options: -threaded + -rtsopts + -with-rtsopts=-N + build-tool-depends: hspec-discover:hspec-discover diff --git a/vendors/datadog/src/OpenTelemetry/Vendor/Datadog.hs b/vendors/datadog/src/OpenTelemetry/Vendor/Datadog.hs new file mode 100644 index 00000000..71097385 --- /dev/null +++ b/vendors/datadog/src/OpenTelemetry/Vendor/Datadog.hs @@ -0,0 +1,80 @@ +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE TupleSections #-} + +module OpenTelemetry.Vendor.Datadog ( + -- * Trace + -- + -- | These functions are conversions of the hs-opentelemetry internal representation of the trace ID and + -- the span ID and the Datadog header representation of them each other. + -- + -- @ + -- +----------+-----------------+----------------+ + -- | | Trace ID | Span ID | + -- +----------+-----------------+----------------+ + -- | Internal | 128-bit integer | 64-bit integer | + -- +----------+-----------------+----------------+ + -- | Datadog | ASCII text of | ASCII text of | + -- | Header | 64-bit integer | 64-bit integer | + -- +----------+-----------------+----------------+ + -- @ + -- + -- Reference: bi-directional conversion of IDs of Open Telemetry and ones of Datadog + -- + -- - English: https://docs.datadoghq.com/tracing/other_telemetry/connect_logs_and_traces/opentelemetry/ + -- - Japanese: https://docs.datadoghq.com/ja/tracing/connect_logs_and_traces/opentelemetry/ + convertOpenTelemetrySpanIdToDatadogSpanId, + convertOpenTelemetryTraceIdToDatadogTraceId, + + -- * Attribute + -- + -- | These are keys to lookup or insert 'OpenTelemetry.Attributes.Attribute's to 'OpenTelemetry.Attributes.Attributes' with. + envKey, + serviceKey, + versionKey, + + -- * Resource + detectResource, +) where + +import qualified Data.ByteString.Short.Internal as SBI +import Data.Primitive (ByteArray (ByteArray)) +import Data.String (fromString) +import Data.Text (Text) +import Data.Word (Word64) +import qualified OpenTelemetry.Internal.Trace.Id as Trace +import OpenTelemetry.Resource (Resource, mkResource) +import OpenTelemetry.Vendor.Datadog.Internal (indexByteArrayNbo) +import System.Environment (lookupEnv) + + +convertOpenTelemetrySpanIdToDatadogSpanId :: Trace.SpanId -> Word64 +convertOpenTelemetrySpanIdToDatadogSpanId (Trace.SpanId (SBI.SBS a)) = indexByteArrayNbo (ByteArray a) 0 + + +convertOpenTelemetryTraceIdToDatadogTraceId :: Trace.TraceId -> Word64 +convertOpenTelemetryTraceIdToDatadogTraceId (Trace.TraceId (SBI.SBS a)) = indexByteArrayNbo (ByteArray a) 1 + + +envKey :: Text +envKey = "dd.env" + + +serviceKey :: Text +serviceKey = "dd.service" + + +versionKey :: Text +versionKey = "dd.version" + + +-- | Detect these environment variables and create a 'Resource' from them. +-- +-- - DD_ENV +-- - DD_SERVICE +-- - DD_VERSION +detectResource :: IO (Resource r) +detectResource = do + env <- (envKey,) <$> lookupEnv "DD_ENV" + service <- (serviceKey,) <$> lookupEnv "DD_SERVICE" + version <- (versionKey,) <$> lookupEnv "DD_VERSION" + pure $ mkResource $ (\(k, mv) -> (k,) . fromString <$> mv) <$> [env, service, version] diff --git a/vendors/datadog/src/OpenTelemetry/Vendor/Datadog/Internal.hs b/vendors/datadog/src/OpenTelemetry/Vendor/Datadog/Internal.hs new file mode 100644 index 00000000..9695fb96 --- /dev/null +++ b/vendors/datadog/src/OpenTelemetry/Vendor/Datadog/Internal.hs @@ -0,0 +1,22 @@ +module OpenTelemetry.Vendor.Datadog.Internal (indexByteArrayNbo) where + +import Data.Bits (Bits (shift)) +import Data.Primitive.ByteArray (ByteArray (), indexByteArray) +import Data.Word (Word64, Word8) + + +-- | Read 'ByteArray' to 'Word64' with network-byte-order. +indexByteArrayNbo :: + ByteArray -> + -- | Offset in 'Word64'-size unit + Int -> + Word64 +indexByteArrayNbo ba offset = + loop 0 0 + where + loop 8 acc = acc + loop n acc = loop (n + 1) $ shift acc 8 + word8ToWord64 (indexByteArray ba $ 8 * offset + n) + + +word8ToWord64 :: Word8 -> Word64 +word8ToWord64 = fromIntegral diff --git a/propagators/datadog/test/spec/OpenTelemetry/Propagator/DatadogSpec.hs b/vendors/datadog/test/spec/OpenTelemetry/Vendor/DatadogSpec.hs similarity index 94% rename from propagators/datadog/test/spec/OpenTelemetry/Propagator/DatadogSpec.hs rename to vendors/datadog/test/spec/OpenTelemetry/Vendor/DatadogSpec.hs index 34c90e3d..6af358eb 100644 --- a/propagators/datadog/test/spec/OpenTelemetry/Propagator/DatadogSpec.hs +++ b/vendors/datadog/test/spec/OpenTelemetry/Vendor/DatadogSpec.hs @@ -2,12 +2,12 @@ {-# LANGUAGE OverloadedStrings #-} {-# OPTIONS_GHC -Wno-type-defaults #-} -module OpenTelemetry.Propagator.DatadogSpec where +module OpenTelemetry.Vendor.DatadogSpec where import qualified Data.ByteString as B import qualified Data.ByteString.Short as SB import OpenTelemetry.Internal.Trace.Id -import OpenTelemetry.Propagator.Datadog +import OpenTelemetry.Vendor.Datadog import Test.Hspec import Test.QuickCheck diff --git a/vendors/datadog/test/spec/Spec.hs b/vendors/datadog/test/spec/Spec.hs new file mode 100644 index 00000000..038e7c8e --- /dev/null +++ b/vendors/datadog/test/spec/Spec.hs @@ -0,0 +1,2 @@ +{-# OPTIONS_GHC -F -pgmF hspec-discover #-} +