hotel-california 0.0.6.2 → 0.1.0.0
raw patch · 6 files changed
+115/−55 lines, 6 filesdep −hs-opentelemetry-vendor-honeycombdep ~hs-opentelemetry-apidep ~hs-opentelemetry-sdksetup-changedPVP ok
version bump matches the API change (PVP)
Dependencies removed: hs-opentelemetry-vendor-honeycomb
Dependency ranges changed: hs-opentelemetry-api, hs-opentelemetry-sdk
API changes (from Hackage documentation)
+ HotelCalifornia.Tracing: TracingStatus :: Bool -> TracingStatus
+ HotelCalifornia.Tracing: [tracingEnabled] :: TracingStatus -> Bool
+ HotelCalifornia.Tracing: data TracingStatus
+ HotelCalifornia.Tracing: otelTracingEnabled :: IO Bool
- HotelCalifornia.Tracing: withGlobalTracing :: MonadUnliftIO m => (Maybe HoneycombTarget -> m a) -> m a
+ HotelCalifornia.Tracing: withGlobalTracing :: MonadUnliftIO m => (TracingStatus -> m a) -> m a
Files
- CHANGELOG.md +16/−0
- README.md +5/−0
- Setup.hs +1/−0
- app/Main.hs +32/−23
- hotel-california.cabal +7/−10
- src/HotelCalifornia/Tracing.hs +54/−22
CHANGELOG.md view
@@ -8,6 +8,22 @@ ## Unreleased +- [#23](https://github.com/parsonsmatt/hotel-california/pull/23)+ - Tracing is now only initialized when an exporter is configured;+ otherwise tracing is bypassed entirely. Honeycomb is no longer consulted+ to decide whether tracing is on. Following the [OpenTelemetry+ environment variable specification](https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/):+ - `OTEL_SDK_DISABLED=true` (case-insensitive) disables tracing.+ - `OTEL_TRACES_EXPORTER=none` disables tracing; any other non-empty+ value enables it.+ - Otherwise, tracing is enabled iff any `OTEL_EXPORTER_*` environment+ variable is set with a non-empty value.+ - Environment variables set to the empty string are treated as unset.+ - Breaking change: the callback to `withGlobalTracing` now receives a+ `TracingStatus` record (instead of `Maybe HoneycombTarget`), which+ carries a `tracingEnabled` field. Downstream consumers that want+ Honeycomb trace links can set those up themselves.+ ## 0.0.6.2 - 2026-06-25 - [#25](https://github.com/parsonsmatt/hotel-california/pull/25)
README.md view
@@ -39,6 +39,11 @@ [`hs-opentelemetry-sdk`](https://hackage.haskell.org/package/hs-opentelemetry-sdk) for more information +Tracing is opt-in: it is enabled when `OTEL_TRACES_EXPORTER` is set (to+anything other than `none`), or when any `OTEL_EXPORTER_*` environment+variable is set with a non-empty value. Setting `OTEL_SDK_DISABLED=true`+disables tracing regardless of any other configuration.+ # Background/FAQ ## Lol what's up with the name
Setup.hs view
@@ -1,2 +1,3 @@ import Distribution.Simple+ main = defaultMain
app/Main.hs view
@@ -1,11 +1,11 @@ module Main where import Data.Version (showVersion)-import Paths_hotel_california (version) import HotelCalifornia.Exec-import HotelCalifornia.Tracing (withGlobalTracing)+import HotelCalifornia.Tracing (TracingStatus (..), withGlobalTracing) import Options.Applicative import Options.Applicative.Help.Pretty (Doc, vsep)+import Paths_hotel_california (version) data Command = Command { commandGlobalOptions :: GlobalOptions@@ -18,49 +18,58 @@ = Exec ExecArgs programDescription :: Doc-programDescription = vsep- [ "`hotel-california` is a tool for OTel tracing of shell scripts, inspired by `otel-cli`."- , "For help with a command, say `hotel COMMAND --help`. Currently, the only supported command is `exec`."- , ""- , "Check out the repository any time you like at https://github.com/parsonsmatt/hotel-california."- ]+programDescription =+ vsep+ [ "`hotel-california` is a tool for OTel tracing of shell scripts, inspired by `otel-cli`."+ , "For help with a command, say `hotel COMMAND --help`. Currently, the only supported command is `exec`."+ , ""+ , "Check out the repository any time you like at https://github.com/parsonsmatt/hotel-california."+ ] optionsParser :: ParserInfo Command optionsParser = info' parser' programDescription where- -- thanks danidiaz for the blog post+ -- thanks danidiaz for the blog post info' :: Parser a -> Doc -> ParserInfo a- info' p descDoc = info- (helper <*> p)- (fullDesc <> progDescDoc (Just descDoc) <> noIntersperse)+ info' p descDoc =+ info+ (helper <*> p)+ (fullDesc <> progDescDoc (Just descDoc) <> noIntersperse) parser' :: Parser Command parser' = Command <$> generalOptionsParser <*> subCommandParser- <**> simpleVersioner (showVersion version)+ <**> simpleVersioner (showVersion version) generalOptionsParser = pure GlobalOptions subCommandParser :: Parser SubCommand subCommandParser =- subparser $ foldMap command'- [ ("exec", "Execute the given command with tracing enabled", Exec <$> parseExecArgs)- ]+ subparser $+ foldMap+ command'+ [+ ( "exec"+ , "Execute the given command with tracing enabled"+ , Exec <$> parseExecArgs+ )+ ] - command' (cmdName,desc,parser) =+ command' (cmdName, desc, parser) = command cmdName (info' parser desc) main :: IO () main = do- withGlobalTracing $ \mTarget -> do- let parserPrefs = defaultPrefs{ prefMultiSuffix = "..." }- Command {..} <- customExecParser parserPrefs optionsParser+ withGlobalTracing $ \tracingStatus -> do+ let+ parserPrefs = defaultPrefs{prefMultiSuffix = "..."}+ Command{..} <- customExecParser parserPrefs optionsParser case commandSubCommand of Exec execArgs ->- case mTarget of- Just _target -> runExecArgs execArgs- Nothing -> runNoTracing $ execArgsSubprocess execArgs+ if tracingStatus.tracingEnabled+ then runExecArgs execArgs+ else runNoTracing $ execArgsSubprocess execArgs
hotel-california.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack name: hotel-california-version: 0.0.6.2+version: 0.1.0.0 description: Please see the README on GitHub at <https://github.com/parsonsmatt/hotel-california#readme> homepage: https://github.com/parsonsmatt/hotel-california#readme bug-reports: https://github.com/parsonsmatt/hotel-california/issues@@ -77,12 +77,11 @@ , bytestring , directory , filepath- , hs-opentelemetry-api >=0.1.0.0+ , hs-opentelemetry-api >=0.3.0.0 , hs-opentelemetry-exporter-otlp , hs-opentelemetry-propagator-w3c- , hs-opentelemetry-sdk >=0.0.3.6+ , hs-opentelemetry-sdk >=0.1.0.1 , hs-opentelemetry-utils-exceptions- , hs-opentelemetry-vendor-honeycomb , http-types , optparse-applicative , posix-escape@@ -143,12 +142,11 @@ , directory , filepath , hotel-california- , hs-opentelemetry-api >=0.1.0.0+ , hs-opentelemetry-api >=0.3.0.0 , hs-opentelemetry-exporter-otlp , hs-opentelemetry-propagator-w3c- , hs-opentelemetry-sdk >=0.0.3.6+ , hs-opentelemetry-sdk >=0.1.0.1 , hs-opentelemetry-utils-exceptions- , hs-opentelemetry-vendor-honeycomb , http-types , optparse-applicative , posix-escape@@ -210,12 +208,11 @@ , directory , filepath , hotel-california- , hs-opentelemetry-api >=0.1.0.0+ , hs-opentelemetry-api >=0.3.0.0 , hs-opentelemetry-exporter-otlp , hs-opentelemetry-propagator-w3c- , hs-opentelemetry-sdk >=0.0.3.6+ , hs-opentelemetry-sdk >=0.1.0.1 , hs-opentelemetry-utils-exceptions- , hs-opentelemetry-vendor-honeycomb , http-types , optparse-applicative , posix-escape
src/HotelCalifornia/Tracing.hs view
@@ -6,9 +6,10 @@ ) where import Control.Monad-import Data.ByteString.Char8 qualified as BS8+import Data.Char (toLower)+import Data.List (isPrefixOf)+import Data.Maybe (isJust) import Data.Text (Text)-import Data.Time import HotelCalifornia.Tracing.TraceParent import OpenTelemetry.Context as Context hiding (lookup) import OpenTelemetry.Context.ThreadLocal (attachContext)@@ -23,7 +24,7 @@ , inSpan'' ) import OpenTelemetry.Trace qualified as Trace-import OpenTelemetry.Vendor.Honeycomb qualified as Honeycomb+import System.Environment (getEnvironment) import UnliftIO -- | Initialize the global tracing provider for the application and run an action@@ -31,29 +32,61 @@ -- up the provider afterwards. -- -- This also sets up an empty context (creating a new trace ID).-withGlobalTracing- :: (MonadUnliftIO m) => (Maybe Honeycomb.HoneycombTarget -> m a) -> m a+--+-- The callback receives a 'TracingStatus' describing whether tracing was+-- actually initialized; see 'tracingEnabled'.+withGlobalTracing :: (MonadUnliftIO m) => (TracingStatus -> m a) -> m a withGlobalTracing act = do void $ attachContext Context.empty liftIO setParentSpanFromEnvironment- withTracer $ \_ -> do- -- note: this is not in a span since we don't have a root span yet so it- -- would not wind up in the trace in a helpful way anyway- mTarget <-- Honeycomb.getOrInitializeHoneycombTargetInContext initializationTimeout- `catch` \(e :: SomeException) -> do- -- we are too early in initialization to be able to use a normal logger,- -- but this needs to get out somehow.- --- -- honeycomb links are not load-bearing, so we let them just not come- -- up if the API fails.- liftIO . BS8.hPutStrLn stderr $- "error setting up Honeycomb trace links: " <> (BS8.pack $ displayException e)- pure Nothing+ enabled <- liftIO otelTracingEnabled+ if enabled+ then withTracer $ \_ -> act TracingStatus{tracingEnabled = True}+ else act TracingStatus{tracingEnabled = False} - act mTarget+-- | The result of setting up tracing, passed to the callback of+-- 'withGlobalTracing'.+data TracingStatus = TracingStatus+ { tracingEnabled :: Bool+ -- ^ 'True' when an exporter is configured (see 'otelTracingEnabled') and+ -- tracing has been initialized, and 'False' otherwise -- in which case+ -- the caller should bypass tracing.+ }++-- | Decide whether tracing should be initialized, following the OpenTelemetry+-- [environment variable specification](https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/)+-- where practical:+--+-- * @OTEL_SDK_DISABLED=true@ (case-insensitive) disables tracing.+-- * @OTEL_TRACES_EXPORTER=none@ disables tracing; any other non-empty value+-- enables it.+-- * Otherwise, tracing is enabled iff any @OTEL_EXPORTER_*@ environment+-- variable is set with a non-empty value.+--+-- The spec would have tracing enabled unconditionally, with+-- @OTEL_TRACES_EXPORTER@ defaulting to an OTLP exporter aimed at+-- @localhost@; since running with no collector at all is the common case+-- for a CLI tool, we deviate and treat exporter configuration as opt-in.+--+-- Per the spec, an environment variable set to the empty string is treated+-- the same as unset.+otelTracingEnabled :: IO Bool+otelTracingEnabled = do+ env <- getEnvironment+ let+ getVar key = do+ value <- lookup key env+ guard $ not $ null value+ pure $ map toLower value+ sdkDisabled = getVar "OTEL_SDK_DISABLED" == Just "true"+ tracesExporter = getVar "OTEL_TRACES_EXPORTER"+ hasOtelExporterVar = any isOtelExporterVar env+ pure $+ not sdkDisabled+ && tracesExporter /= Just "none"+ && (isJust tracesExporter || hasOtelExporterVar) where- initializationTimeout = secondsToNominalDiffTime 1+ isOtelExporterVar (k, v) = "OTEL_EXPORTER_" `isPrefixOf` k && not (null v) globalTracer :: (MonadIO m) => m Tracer globalTracer =@@ -76,7 +109,6 @@ inSpan :: (MonadUnliftIO m) => Text -> m a -> m a inSpan spanName = inSpanWith spanName defaultSpanArguments- withTracer :: (MonadUnliftIO m) => (TracerProvider -> m a) -> m a withTracer = bracket (liftIO initializeGlobalTracerProvider) shutdown