Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update HTTP Semantic Conventions to Stable Versions #118

Merged
merged 43 commits into from
May 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
5330fa4
Work in Progress: Request and Response Attributes updated to match th…
evanlauer1 May 14, 2024
5e1bab4
Added Stable attributes to instrumentResponse
evanlauer1 May 15, 2024
178e3b8
Refactored to fit new httpTracerProvider return type
evanlauer1 May 16, 2024
b4bff14
Fixed missing "do" notation and removed unnecessary imports
evanlauer1 May 16, 2024
b18b623
Fix typo and update comment
evanlauer1 May 17, 2024
e5af40c
Found unchanged http name
evanlauer1 May 17, 2024
9309250
Found outdated http attribute names
evanlauer1 May 17, 2024
64c1331
Fixed cradle so HLS works
evanlauer1 May 20, 2024
39ff844
Added Settings File for application-wide environment variable configu…
evanlauer1 May 20, 2024
f9e987c
Moved semConvStabilityOptIn and related types to OpenTelemetry.Settings
evanlauer1 May 20, 2024
3e853aa
Changed code using HttpTracerProvider to work with changed return type
evanlauer1 May 20, 2024
a9520aa
Fixed exports
evanlauer1 May 20, 2024
77538ca
Replaced general Settings.hs with specific SemConvStability.hs
evanlauer1 May 20, 2024
17d2e22
Removed comment because the problem it referenced is solved
evanlauer1 May 20, 2024
32c68be
removed unused language pragma
evanlauer1 May 20, 2024
b28866f
fixed imports
evanlauer1 May 20, 2024
7d92f10
Replaced outdated http conventions based on the value of OTEL_SEMCONV…
evanlauer1 May 21, 2024
5200465
changed line about generation version
evanlauer1 May 21, 2024
1a1aba1
added unordered-containers to dependencies
evanlauer1 May 21, 2024
29bf4d7
Moved semConvStabilityOptIn so that it is in scope
evanlauer1 May 21, 2024
c2ea53f
Updated dependencies for testing
evanlauer1 May 21, 2024
6b1baaa
WIP testing for http-client
evanlauer1 May 21, 2024
524faea
Generated by newer version
evanlauer1 May 21, 2024
6da0bef
Removed WIP testing
evanlauer1 May 22, 2024
8a11e96
Updated getSemConvStabilityOptIn so it parses environment variable a…
evanlauer1 May 22, 2024
8b6f9f3
derives Show and Eq for testing purposes
evanlauer1 May 22, 2024
e76b118
Added tests for SemConvStabilityOptIn to make sure environment variab…
evanlauer1 May 22, 2024
3ca8531
Updated Haddock to include blurb about the new HTTP semantic conventions
evanlauer1 May 22, 2024
4669ae3
Removed hspec from dependencies
evanlauer1 May 22, 2024
25d1cf5
Auto-generated change. Removed hspec from build-depends
evanlauer1 May 22, 2024
d8771ed
Added newline to end of file
evanlauer1 May 22, 2024
76f062e
Split off parsing logic from getSemConvStabilityOptIn to parseSemConv…
evanlauer1 May 22, 2024
5542954
Added blank line for readability
evanlauer1 May 22, 2024
234e43e
Changed pure to Just to improve readability and contrast with Nothing
evanlauer1 May 22, 2024
266b974
Rewrote tests to eliminate boilerplate and increase readability
evanlauer1 May 23, 2024
73c5dca
Refactored and Renamed SemanticsConfig.hs to future proof
evanlauer1 May 23, 2024
591ac8c
Refactored SemanticsConfig so options are Enums for pattern matching …
evanlauer1 May 24, 2024
77b4c5f
Updated SemanticsConfig tests. NOTE: does not currently pass memoizat…
evanlauer1 May 24, 2024
e6b7fc4
Updated to match changes to SemanticsConfig.hs
evanlauer1 May 24, 2024
e0179a4
Fix infinite loop issue
evanlauer1 May 24, 2024
ac5546f
changed from . to $
evanlauer1 May 24, 2024
9523dad
Added haddocks
evanlauer1 May 24, 2024
36fd483
Formatting fixes
evanlauer1 May 28, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion api/hs-opentelemetry-api.cabal
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
cabal-version: 1.12

-- This file has been generated from package.yaml by hpack version 0.35.2.
-- This file has been generated from package.yaml by hpack version 0.36.0.
--
-- see: https://github.com/sol/hpack

Expand Down Expand Up @@ -52,6 +52,7 @@ library
OpenTelemetry.Resource.Service
OpenTelemetry.Resource.Telemetry
OpenTelemetry.Resource.Webengine
OpenTelemetry.SemanticsConfig
OpenTelemetry.Trace.Core
OpenTelemetry.Trace.Id
OpenTelemetry.Trace.Id.Generator
Expand Down Expand Up @@ -83,6 +84,7 @@ library
, http-types
, memory
, mtl
, safe-exceptions
, template-haskell
, text
, thread-utils-context ==0.3.*
Expand All @@ -99,6 +101,7 @@ test-suite hs-opentelemetry-api-test
main-is: Spec.hs
other-modules:
OpenTelemetry.BaggageSpec
OpenTelemetry.SemanticsConfigSpec
OpenTelemetry.Trace.SamplerSpec
OpenTelemetry.Trace.TraceFlagsSpec
Paths_hs_opentelemetry_api
Expand All @@ -124,6 +127,7 @@ test-suite hs-opentelemetry-api-test
, http-types
, memory
, mtl
, safe-exceptions
, template-haskell
, text
, thread-utils-context ==0.3.*
Expand Down
1 change: 1 addition & 0 deletions api/package.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ dependencies:
- ghc-prim
- unliftio-core
- vector-builder
- safe-exceptions

library:
source-dirs: src
Expand Down
90 changes: 90 additions & 0 deletions api/src/OpenTelemetry/SemanticsConfig.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
{-# LANGUAGE OverloadedStrings #-}

module OpenTelemetry.SemanticsConfig (
SemanticsOptions (httpOption),
HttpOption (..),
getSemanticsOptions,
getSemanticsOptions',
) where

import Control.Exception.Safe (throwIO, tryAny)
import Data.IORef (newIORef, readIORef, writeIORef)
import qualified Data.Text as T
import System.Environment (lookupEnv)
import System.IO.Unsafe (unsafePerformIO)


{- | This is a record that contains options for whether the new stable semantics conventions should be emitted.
Semantics conventions that have been declared stable:
- [http](https://opentelemetry.io/blog/2023/http-conventions-declared-stable/#migration-plan)
-}
data SemanticsOptions = SemanticsOptions {httpOption :: HttpOption}


-- | This option determines whether stable, old, or both kinds of http attributes are emitted.
data HttpOption
= Stable
| StableAndOld
| Old
deriving (Show, Eq)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I used this instead of set membership because I did not like that if the pattern was to use when (useStableHttpSemantics options) useStableAttributes it would be easy to forget to check both useStable and useOld because the compiler does not enforce it. This way, the compiler will say "missing cases in pattern match".


-- | These are the default values emitted if OTEL_SEM_CONV_STABILITY_OPT_IN is unset or does not contain values for a specific category of option.
defaultOptions :: SemanticsOptions
defaultOptions = SemanticsOptions {httpOption = Old}


-- | Detects the presence of "http/dup" or "http" in OTEL_SEMCONV_STABILITY_OPT_IN or uses the default option if they are not there.
parseHttpOption :: (Foldable t) => t T.Text -> HttpOption
parseHttpOption envs
| "http/dup" `elem` envs = StableAndOld
| "http" `elem` envs = Stable
| otherwise = httpOption defaultOptions
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using httpOption defaultOptions means that the value if the environment variable is unset will always be the same as if it is set but missing configuration for http.



-- | Detects the presence of semantics options in OTEL_SEMCONV_STABILITY_OPT_IN or uses the defaultOptions if they are not present.
parseSemanticsOptions :: Maybe String -> SemanticsOptions
parseSemanticsOptions Nothing = defaultOptions
parseSemanticsOptions (Just env) = SemanticsOptions {..}
where
envs = fmap T.strip $ T.splitOn "," $ T.pack env
httpOption = parseHttpOption envs
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The compiler will give a warning if one of the fields is unset.



{- | Version of getSemanticsOptions that is not memoized. It is recommended to use getSemanticsOptions for efficiency purposes
unless it is necessary to retrieve the value of OTEL_SEMCONV_STABILITY_OPT_IN every time getSemanticsOptions' is called.
-}
getSemanticsOptions' :: IO SemanticsOptions
getSemanticsOptions' = parseSemanticsOptions <$> lookupEnv "OTEL_SEMCONV_STABILITY_OPT_IN"
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I used function' to indicate a different version of function. I'm not sure if that is the best way to indicate the difference. I want function to be the default and function' to only be used in necessary circumstances.



{- | Create a new memoized IO action using an 'IORef' under the surface. Note that
the action may be run in multiple threads simultaneously, so this may not be
thread safe (depending on the underlying action). For the sake of reading an environment
variable and parsing some stuff, we don't have to be concerned about thread-safety.
-}
memoize :: IO a -> IO (IO a)
memoize action = do
ref <- newIORef Nothing
pure $ do
mres <- readIORef ref
res <- case mres of
Just res -> pure res
Nothing -> do
res <- tryAny action
writeIORef ref $ Just res
pure res
either throwIO pure res


{- | Retrieves OTEL_SEMCONV_STABILITY_OPT_IN and parses it into SemanticsOptions.

This uses the [global IORef trick](https://www.parsonsmatt.org/2021/04/21/global_ioref_in_template_haskell.html)
to memoize the settings for efficiency. Note that getSemanticsOptions stores and returns the
value of the first time it was called and will not change when OTEL_SEMCONV_STABILITY_OPT_IN
is updated. Use getSemanticsOptions' to read OTEL_SEMCONV_STABILITY_OPT_IN every time the
function is called.
-}
getSemanticsOptions :: IO SemanticsOptions
getSemanticsOptions = unsafePerformIO $ memoize getSemanticsOptions'
{-# NOINLINE getSemanticsOptions #-}
19 changes: 10 additions & 9 deletions api/src/OpenTelemetry/Trace/Core.hs
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ createSpanWithoutCallStack t ctxt n args@SpanArguments {..} = liftIO $ do
(H.unions [additionalInfo, attrs, attributes])
, spanLinks =
let limitedLinks = fromMaybe 128 (linkCountLimit $ tracerProviderSpanLimits $ tracerProvider t)
in frozenBoundedCollection limitedLinks $ fmap freezeLink links
in frozenBoundedCollection limitedLinks $ fmap freezeLink links
, spanEvents = emptyAppendOnlyBoundedCollection $ fromMaybe 128 (eventCountLimit $ tracerProviderSpanLimits $ tracerProvider t)
, spanStatus = Unset
, spanStart = st
Expand Down Expand Up @@ -316,13 +316,14 @@ callerAttributes = case getCallStack callStack of


srcAttributes :: (String, SrcLoc) -> H.HashMap Text Attribute
srcAttributes (fn, loc) = H.fromList
[ ("code.function", toAttribute $ T.pack fn)
, ("code.namespace", toAttribute $ T.pack $ srcLocModule loc)
, ("code.filepath", toAttribute $ T.pack $ srcLocFile loc)
, ("code.lineno", toAttribute $ srcLocStartLine loc)
, ("code.package", toAttribute $ T.pack $ srcLocPackage loc)
]
srcAttributes (fn, loc) =
H.fromList
[ ("code.function", toAttribute $ T.pack fn)
, ("code.namespace", toAttribute $ T.pack $ srcLocModule loc)
, ("code.filepath", toAttribute $ T.pack $ srcLocFile loc)
, ("code.lineno", toAttribute $ srcLocStartLine loc)
, ("code.package", toAttribute $ T.pack $ srcLocPackage loc)
]


{- | Attributes are added to the end of the span argument list, so will be discarded
Expand Down Expand Up @@ -555,7 +556,7 @@ endSpan (Span s) mts = liftIO $ do
ts <- maybe getTimestamp pure mts
(alreadyFinished, frozenS) <- atomicModifyIORef' s $ \(!i) ->
let ref = i {spanEnd = spanEnd i <|> Just ts}
in (ref, (isJust $ spanEnd i, ref))
in (ref, (isJust $ spanEnd i, ref))
unless alreadyFinished $ do
eResult <- try $ mapM_ (`processorOnEnd` s) $ tracerProviderProcessors $ tracerProvider $ spanTracer frozenS
case eResult of
Expand Down
16 changes: 8 additions & 8 deletions api/src/OpenTelemetry/Util.hs
Original file line number Diff line number Diff line change
Expand Up @@ -103,14 +103,14 @@ data AppendOnlyBoundedCollection a = AppendOnlyBoundedCollection
instance forall a. (Show a) => Show (AppendOnlyBoundedCollection a) where
showsPrec d AppendOnlyBoundedCollection {collection = c, maxSize = m, dropped = r} =
let vec = Builder.build c :: V.Vector a
in showParen (d > 10) $
showString "AppendOnlyBoundedCollection {collection = "
. shows vec
. showString ", maxSize = "
. shows m
. showString ", dropped = "
. shows r
. showString "}"
in showParen (d > 10) $
showString "AppendOnlyBoundedCollection {collection = "
. shows vec
. showString ", maxSize = "
. shows m
. showString ", dropped = "
. shows r
. showString "}"


-- | Initialize a bounded collection that admits a maximum size
Expand Down
44 changes: 44 additions & 0 deletions api/test/OpenTelemetry/SemanticsConfigSpec.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
module OpenTelemetry.SemanticsConfigSpec where

import OpenTelemetry.SemanticsConfig
import System.Environment
import Test.Hspec


envVarName :: String
envVarName = "OTEL_SEMCONV_STABILITY_OPT_IN"


spec :: Spec
spec = do
describe "SemanticsConfig" $ do
describe "HttpOption" $ do
it "defaults to 'Old' when env var has no value" $ do
unsetEnv envVarName
semanticsOptions <- getSemanticsOptions'
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uses getSemanticsOptions' so that the tests are not affected by memoization. Memoization is tested later.

httpOption semanticsOptions `shouldBe` Old
mapM_
( \(envVarVal, expectedVal) ->
it ("returns " ++ show expectedVal ++ " when env var is " ++ show envVarVal) $ do
setEnv envVarName envVarVal
semanticsOptions <- getSemanticsOptions'
httpOption semanticsOptions `shouldBe` expectedVal
)
[ ("http", Stable)
, ("http/du", Old) -- intentionally similar to both "http/dup" and "http"
, ("http/dup", StableAndOld)
, ("http/dup,http", StableAndOld)
, ("http,http/dup", StableAndOld)
, ("http,something-random,http/dup", StableAndOld)
]
context "memoization" $ do
it "works" $ do
setEnv envVarName "http"
semanticsOptions <- getSemanticsOptions
httpOption semanticsOptions `shouldBe` Stable
it ("does not change when " ++ envVarName ++ " changes") $ do
setEnv envVarName "http"
semanticsOptions <- getSemanticsOptions
setEnv envVarName "http/dup"
semanticsOptions <- getSemanticsOptions
httpOption semanticsOptions `shouldBe` Stable -- and not StableAndOld because of memoization
2 changes: 2 additions & 0 deletions api/test/Spec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import OpenTelemetry.Attributes (lookupAttribute)

import qualified OpenTelemetry.BaggageSpec as Baggage
import OpenTelemetry.Context
import qualified OpenTelemetry.SemanticsConfigSpec as SemanticsConfigSpec
import OpenTelemetry.Trace.Core
import qualified OpenTelemetry.Trace.SamplerSpec as Sampler
import qualified OpenTelemetry.Trace.TraceFlagsSpec as TraceFlags
Expand Down Expand Up @@ -54,3 +55,4 @@ main = hspec $ do
Baggage.spec
Sampler.spec
TraceFlags.spec
SemanticsConfigSpec.spec
14 changes: 7 additions & 7 deletions exporters/otlp/src/OpenTelemetry/Exporter/OTLP.hs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE NumericUnderscores #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ScopedTypeVariables #-}

-----------------------------------------------------------------------------

Expand Down Expand Up @@ -283,13 +283,13 @@ otlpExporter conf = do
Left err@(HttpExceptionRequest req e)
| HTTPClient.host req == "localhost"
, HTTPClient.port req == 4317 || HTTPClient.port req == 4318
, ConnectionFailure _someExn <- e
-> do
pure $ Failure Nothing
, ConnectionFailure _someExn <- e ->
do
pure $ Failure Nothing
| otherwise ->
if isRetryableException e
then exponentialBackoff
else pure $ Failure $ Just $ SomeException err
if isRetryableException e
then exponentialBackoff
else pure $ Failure $ Just $ SomeException err
Left err -> do
pure $ Failure $ Just $ SomeException err
Right resp ->
Expand Down
31 changes: 23 additions & 8 deletions hie.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ cradle:
- path: "api/test"
component: "hs-opentelemetry-api:test:hs-opentelemetry-api-test"

- path: "examples/hspec/src"
component: "hspec-example:lib"

- path: "examples/hspec/test"
component: "hspec-example:test:test"

- path: "examples/yesod-minimal/src"
component: "yesod-minimal:lib"

Expand Down Expand Up @@ -90,8 +96,8 @@ cradle:
- path: "propagators/b3/src"
component: "hs-opentelemetry-propagator-b3:lib"

- path: "propagators/b3/test/spec"
component: "hs-opentelemetry-propagator-b3:test:spec"
- path: "propagators/b3/test"
component: "hs-opentelemetry-propagator-b3:test:hs-opentelemetry-propagator-b3-test"

- path: "propagators/datadog/src"
component: "hs-opentelemetry-propagator-datadog:lib"
Expand All @@ -105,6 +111,21 @@ cradle:
- path: "propagators/datadog/benchmark/header-codec/main.hs"
component: "hs-opentelemetry-propagator-datadog:bench:header-codec"

- path: "propagators/datadog/old-src/main.hs"
component: "hs-opentelemetry-propagator-datadog:bench:header-codec"

- path: "propagators/datadog/benchmark/header-codec/Raw.hs"
component: "hs-opentelemetry-propagator-datadog:bench:header-codec"

- path: "propagators/datadog/benchmark/header-codec/String.hs"
component: "hs-opentelemetry-propagator-datadog:bench:header-codec"

- path: "propagators/datadog/old-src/Raw.hs"
component: "hs-opentelemetry-propagator-datadog:bench:header-codec"

- path: "propagators/datadog/old-src/String.hs"
component: "hs-opentelemetry-propagator-datadog:bench:header-codec"

- path: "propagators/w3c/src"
component: "hs-opentelemetry-propagator-w3c:lib"

Expand All @@ -116,9 +137,3 @@ cradle:

- path: "sdk/test"
component: "hs-opentelemetry-sdk:test:hs-opentelemetry-sdk-test"

- path: "utils/exceptions/src"
component: "hs-opentelemetry-utils-exceptions:lib"

- path: "utils/exceptions/test"
component: "hs-opentelemetry-utils-exceptions:test:exceptions-test"
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE OverloadedLists #-}
{-# LANGUAGE OverloadedStrings #-}

module OpenTelemetry.Instrumentation.Conduit where

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
cabal-version: 1.12

-- This file has been generated from package.yaml by hpack version 0.35.2.
-- This file has been generated from package.yaml by hpack version 0.36.0.
--
-- see: https://github.com/sol/hpack

Expand Down
Loading
Loading