| Copyright | (c) Ian Duncan 2026 |
|---|---|
| License | BSD-3 |
| Stability | experimental |
| Safe Haskell | None |
| Language | Haskell2010 |
OpenTelemetry.Log.Core
Description
Overview
This module provides the Logs Bridge API for connecting existing logging
systems (e.g. monad-logger, katip, co-log) to OpenTelemetry. It is
not intended as a direct logging API for end users; instead, it gives
logging library authors the hooks to route log records through the
OpenTelemetry pipeline (processors, exporters, and correlation with traces).
Quick example
import OpenTelemetry.Log.Core
main :: IO ()
main = do
-- Create a provider (typically done by the SDK during initialization)
lp <- createLoggerProvider processors emptyLoggerProviderOptions
let logger = makeLogger lp "my-app"
-- Emit a log record
emitLogRecord logger $ LogRecordArguments
{ severityNumber = Just SeverityNumberInfo
, severityText = Just INFO
, body = Just (toValue ("User logged in" :: Text))
, attributes = mempty
, timestamp = Nothing
, observedTimestamp = Nothing
, traceContext = Nothing
, instrumentationAttributes = Nothing
}
Key concepts
LoggerProvider- Factory for
Loggers. Holds processors, resource info, and attribute limits. Create withcreateLoggerProvider. Logger- Obtained from a
LoggerProvider, scoped to an instrumentation library. UsemakeLoggerorgetLogger. LogRecord- A single log entry with severity, body, attributes, and
optional correlation to a trace span. Emitted via
emitLogRecord.
Severity filtering
You can set a minimum severity level to suppress low-priority logs:
setLoggerMinSeverity lp (Just SeverityNumberWarn) -- Now only WARN and above are emitted
Both loggerIsEnabled and emitLogRecord respect this threshold.
Use Nothing to disable filtering.
Spec reference
Synopsis
- data LoggerProvider = LoggerProvider {
- loggerProviderProcessors :: Vector LogRecordProcessor
- loggerProviderResource :: MaterializedResources
- loggerProviderAttributeLimits :: AttributeLimits
- loggerProviderIsShutdown :: IORef Bool
- loggerProviderHasProcessors :: !Bool
- loggerProviderOnEmit :: ReadWriteLogRecord -> Context -> IO ()
- loggerProviderMinSeverity :: IORef (Maybe SeverityNumber)
- loggerProviderLoggerCache :: IORef (HashMap InstrumentationLibrary Logger)
- data LoggerProviderOptions = LoggerProviderOptions {}
- emptyLoggerProviderOptions :: LoggerProviderOptions
- createLoggerProvider :: MonadIO m => [LogRecordProcessor] -> LoggerProviderOptions -> m LoggerProvider
- setGlobalLoggerProvider :: MonadIO m => LoggerProvider -> m ()
- getGlobalLoggerProvider :: MonadIO m => m LoggerProvider
- shutdownLoggerProvider :: MonadIO m => LoggerProvider -> Maybe Int -> m ShutdownResult
- data ShutdownResult
- forceFlushLoggerProvider :: MonadIO m => LoggerProvider -> Maybe Int -> m FlushResult
- data InstrumentationLibrary = InstrumentationLibrary {}
- instrumentationLibrary :: Text -> Text -> InstrumentationLibrary
- withSchemaUrl :: Text -> InstrumentationLibrary -> InstrumentationLibrary
- withLibraryAttributes :: Attributes -> InstrumentationLibrary -> InstrumentationLibrary
- data Logger = Logger {}
- makeLogger :: LoggerProvider -> InstrumentationLibrary -> Logger
- getLogger :: MonadIO m => LoggerProvider -> InstrumentationLibrary -> m Logger
- loggerIsEnabled :: Logger -> Maybe SeverityNumber -> Maybe Text -> IO Bool
- loggerIsEnabled' :: MonadIO m => Logger -> Maybe SeverityNumber -> Maybe Text -> Maybe Context -> m Bool
- setLoggerMinSeverity :: MonadIO m => LoggerProvider -> Maybe SeverityNumber -> m ()
- getLoggerMinSeverity :: MonadIO m => LoggerProvider -> m (Maybe SeverityNumber)
- data ReadableLogRecord
- data ReadWriteLogRecord
- class IsReadableLogRecord r where
- class IsReadableLogRecord r => IsReadWriteLogRecord r where
- readLogRecordAttributeLimits :: r -> AttributeLimits
- modifyLogRecord :: r -> (ImmutableLogRecord -> ImmutableLogRecord) -> IO ()
- atomicModifyLogRecord :: r -> (ImmutableLogRecord -> (ImmutableLogRecord, b)) -> IO b
- data LogRecordArguments = LogRecordArguments {}
- data AnyValue
- class ToValue a where
- data SeverityNumber
- toShortName :: SeverityNumber -> Maybe Text
- emitLogRecord :: MonadIO m => Logger -> LogRecordArguments -> m ReadWriteLogRecord
- addAttribute :: (IsReadWriteLogRecord r, MonadIO m, ToValue a) => r -> Text -> a -> m ()
- addAttributes :: (IsReadWriteLogRecord r, MonadIO m, ToValue a) => r -> HashMap Text a -> m ()
- logRecordGetAttributes :: (IsReadableLogRecord r, MonadIO m) => r -> m LogAttributes
LoggerProvider operations
data LoggerProvider Source #
Factory for creating Logger instances. Holds processors, resource,
attribute limits, and shutdown state.
All operations on LoggerProvider are safe for concurrent use from multiple threads.
Spec: https://opentelemetry.io/docs/specs/otel/logs/sdk/#loggerprovider
Since: 0.0.1.0
Constructors
| LoggerProvider | |
Fields
| |
data LoggerProviderOptions Source #
Since: 0.0.1.0
Constructors
| LoggerProviderOptions | |
Fields
| |
emptyLoggerProviderOptions :: LoggerProviderOptions Source #
Options for creating a LoggerProvider with no resources and default limits.
In effect, logging is a no-op when using this configuration and no-op Processors.
Since: 0.0.1.0
createLoggerProvider :: MonadIO m => [LogRecordProcessor] -> LoggerProviderOptions -> m LoggerProvider Source #
Initialize a new LoggerProvider
You should generally use getGlobalLoggerProvider for most applications.
Since: 0.0.1.0
setGlobalLoggerProvider :: MonadIO m => LoggerProvider -> m () Source #
Overwrite the globally configured LoggerProvider.
Loggers acquired from the previously installed LoggerProviders
will continue to use that LoggerProviders settings.
Since: 0.0.1.0
getGlobalLoggerProvider :: MonadIO m => m LoggerProvider Source #
Access the globally configured LoggerProvider. This LoggerProvider is no-op until initialized by the SDK
Since: 0.0.1.0
shutdownLoggerProvider Source #
Arguments
| :: MonadIO m | |
| => LoggerProvider | |
| -> Maybe Int | Optional timeout in microseconds, defaults to 5,000,000 (5s) |
| -> m ShutdownResult |
This method provides a way for provider to do any cleanup required.
This will also trigger shutdowns on all internal processors.
Since: 0.0.1.0
data ShutdownResult Source #
Since: 0.0.1.0
Constructors
| ShutdownSuccess | |
| ShutdownFailure | |
| ShutdownTimeout |
Instances
| Show ShutdownResult Source # | |
Defined in OpenTelemetry.Internal.Common.Types Methods showsPrec :: Int -> ShutdownResult -> ShowS # show :: ShutdownResult -> String # showList :: [ShutdownResult] -> ShowS # | |
| Eq ShutdownResult Source # | |
Defined in OpenTelemetry.Internal.Common.Types Methods (==) :: ShutdownResult -> ShutdownResult -> Bool # (/=) :: ShutdownResult -> ShutdownResult -> Bool # | |
forceFlushLoggerProvider Source #
Arguments
| :: MonadIO m | |
| => LoggerProvider | |
| -> Maybe Int | Optional timeout in microseconds, defaults to 5,000,000 (5s) |
| -> m FlushResult | Result that denotes whether the flush action succeeded, failed, or timed out. |
This method provides a way for provider to immediately export all LogRecords that have not yet
been exported for all the internal processors.
Since: 0.0.1.0
Logger operations
data InstrumentationLibrary Source #
An instrumentation scope identifies the library or component providing
instrumentation. The OpenTelemetry specification renamed this concept from
"Instrumentation Library" to "Instrumentation Scope"; this type retains
the old constructor name for backwards compatibility but InstrumentationScope
is the preferred type alias.
Spec: https://opentelemetry.io/docs/specs/otel/common/instrumentation-scope/
Since: 0.0.1.0
Constructors
| InstrumentationLibrary | |
Fields
| |
Instances
instrumentationLibrary :: Text -> Text -> InstrumentationLibrary Source #
Create an InstrumentationLibrary with a name and version.
Schema URL and attributes default to empty.
Prefer instrumentationScope for new code.
Since: 0.4.0.0
withSchemaUrl :: Text -> InstrumentationLibrary -> InstrumentationLibrary Source #
Set the schema URL on an InstrumentationLibrary.
Since: 0.4.0.0
withLibraryAttributes :: Attributes -> InstrumentationLibrary -> InstrumentationLibrary Source #
Set attributes on an InstrumentationLibrary.
Since: 0.4.0.0
LogRecords can be created from Loggers. Loggers are uniquely identified by the libraryName, libraryVersion, schemaUrl fields of InstrumentationLibrary.
Creating two Loggers with the same identity but different libraryAttributes is a user error.
All operations on Logger are safe for concurrent use from multiple threads.
Since: 0.0.1.0
Constructors
| Logger | |
Fields
| |
Arguments
| :: LoggerProvider | The |
| -> InstrumentationLibrary | The library that the |
| -> Logger |
Since: 0.0.1.0
getLogger :: MonadIO m => LoggerProvider -> InstrumentationLibrary -> m Logger Source #
Like makeLogger, but logs a warning when libraryName is empty.
Since: 0.0.1.0
loggerIsEnabled :: Logger -> Maybe SeverityNumber -> Maybe Text -> IO Bool Source #
Returns True if a log record with the given severity (and optional
event name) would be forwarded to processors.
Checks, in order:
- Whether the provider has any registered processors.
- Whether the provider has been shut down.
- Whether the record's severity meets the provider's minimum severity
threshold (set via
LoggerProviderOptionsorsetLoggerMinSeverity).
When the caller passes Nothing for severity, the minimum-severity gate
is skipped (the record is allowed through).
Callers SHOULD invoke this before each log emit to get the most up-to-date response, as the result may change over time.
Since: 0.1.0.0
loggerIsEnabled' :: MonadIO m => Logger -> Maybe SeverityNumber -> Maybe Text -> Maybe Context -> m Bool Source #
Like loggerIsEnabled but accepts an explicit Context.
When Nothing, uses the current implicit context.
Since: 0.4.0.0
setLoggerMinSeverity :: MonadIO m => LoggerProvider -> Maybe SeverityNumber -> m () Source #
Set the minimum severity for a LoggerProvider at runtime.
Log records with a severity below the threshold will be suppressed by
both loggerIsEnabled and emitLogRecord. Pass Nothing to disable
severity filtering (the default).
Since: 0.4.0.0
getLoggerMinSeverity :: MonadIO m => LoggerProvider -> m (Maybe SeverityNumber) Source #
Read the current minimum severity threshold for a LoggerProvider.
Returns Nothing when no severity filtering is active.
Since: 0.4.0.0
LogRecord operations
data ReadableLogRecord Source #
Since: 0.0.1.0
Instances
data ReadWriteLogRecord Source #
This is a data type that can represent logs from various sources: application log files, machine generated events, system logs, etc. Specification outlined here. Existing log formats can be unambiguously mapped to this data type. Reverse mapping from this data type is also possible to the extent that the target log format has equivalent capabilities.
Since: 0.0.1.0
Instances
| IsReadWriteLogRecord ReadWriteLogRecord Source # | |
Defined in OpenTelemetry.Internal.Log.Types Methods readLogRecordAttributeLimits :: ReadWriteLogRecord -> AttributeLimits Source # modifyLogRecord :: ReadWriteLogRecord -> (ImmutableLogRecord -> ImmutableLogRecord) -> IO () Source # atomicModifyLogRecord :: ReadWriteLogRecord -> (ImmutableLogRecord -> (ImmutableLogRecord, b)) -> IO b Source # | |
| IsReadableLogRecord ReadWriteLogRecord Source # | |
class IsReadableLogRecord r where Source #
This is a typeclass representing LogRecords that can be read from.
A function receiving this as an argument MUST be able to access all the information added to the LogRecord. It MUST also be able to access the Instrumentation Scope and Resource information (implicitly) associated with the LogRecord.
The trace context fields MUST be populated from the resolved Context (either the explicitly passed Context or the current Context) when emitted.
Counts for attributes due to collection limits MUST be available for exporters to report as described in the transformation to non-OTLP formats specification.
Since: 0.0.1.0
Methods
readLogRecord :: r -> IO ImmutableLogRecord Source #
Reads the current state of the LogRecord from its internal IORef. The implementation mirrors readIORef.
readLogRecordInstrumentationScope :: r -> InstrumentationLibrary Source #
Reads the InstrumentationScope from the Logger that emitted the LogRecord
readLogRecordResource :: r -> MaterializedResources Source #
Reads the Resource from the LoggerProvider that emitted the LogRecord
class IsReadableLogRecord r => IsReadWriteLogRecord r where Source #
This is a typeclass representing LogRecords that can be read from or written to. All ReadWriteLogRecords are ReadableLogRecords.
A function receiving this as an argument MUST additionally be able to modify the following information added to the LogRecord:
- Timestamp
- ObservedTimestamp
- SeverityText
- SeverityNumber
- Body
- Attributes (addition, modification, removal)
- EventName
- TraceId
- SpanId
- TraceFlags
Since: 0.0.1.0
Methods
readLogRecordAttributeLimits :: r -> AttributeLimits Source #
Reads the attribute limits from the LoggerProvider that emitted the LogRecord. These are needed to add more attributes.
modifyLogRecord :: r -> (ImmutableLogRecord -> ImmutableLogRecord) -> IO () Source #
Atomically modifies the LogRecord using its internal IORef.
Uses atomicModifyIORef' (strict) to avoid thunk buildup and ensure
thread safety under concurrent mutation.
atomicModifyLogRecord :: r -> (ImmutableLogRecord -> (ImmutableLogRecord, b)) -> IO b Source #
Atomically modifies the LogRecord and returns a value.
Uses atomicModifyIORef' (strict) for thread safety.
Instances
| IsReadWriteLogRecord ReadWriteLogRecord Source # | |
Defined in OpenTelemetry.Internal.Log.Types Methods readLogRecordAttributeLimits :: ReadWriteLogRecord -> AttributeLimits Source # modifyLogRecord :: ReadWriteLogRecord -> (ImmutableLogRecord -> ImmutableLogRecord) -> IO () Source # atomicModifyLogRecord :: ReadWriteLogRecord -> (ImmutableLogRecord -> (ImmutableLogRecord, b)) -> IO b Source # | |
data LogRecordArguments Source #
Arguments that may be set on LogRecord creation. If observedTimestamp is not set, it will default to the current timestamp.
If context is not specified it will default to the current context. Refer to the documentation of LogRecord for descriptions
of the fields.
Since: 0.0.1.0
Constructors
| LogRecordArguments | |
Fields
| |
An attribute represents user-provided metadata about a span, link, or event.
Any values are used in place of 'Standard Attributes' in logs because third-party
logs may not conform to the 'Standard Attribute' format.
Telemetry tools may use this data to support high-cardinality querying, visualization in waterfall diagrams, trace sampling decisions, and more.
Since: 0.0.1.0
Constructors
| TextValue Text | |
| BoolValue Bool | |
| DoubleValue Double | |
| IntValue Int64 | |
| ByteStringValue ByteString | |
| ArrayValue [AnyValue] | |
| HashMapValue (HashMap Text AnyValue) | |
| NullValue |
Instances
| Data AnyValue Source # | |||||
Defined in OpenTelemetry.Internal.Common.Types Methods gfoldl :: (forall d b. Data d => c (d -> b) -> d -> c b) -> (forall g. g -> c g) -> AnyValue -> c AnyValue # gunfold :: (forall b r. Data b => c (b -> r) -> c r) -> (forall r. r -> c r) -> Constr -> c AnyValue # toConstr :: AnyValue -> Constr # dataTypeOf :: AnyValue -> DataType # dataCast1 :: Typeable t => (forall d. Data d => c (t d)) -> Maybe (c AnyValue) # dataCast2 :: Typeable t => (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c AnyValue) # gmapT :: (forall b. Data b => b -> b) -> AnyValue -> AnyValue # gmapQl :: (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> AnyValue -> r # gmapQr :: forall r r'. (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> AnyValue -> r # gmapQ :: (forall d. Data d => d -> u) -> AnyValue -> [u] # gmapQi :: Int -> (forall d. Data d => d -> u) -> AnyValue -> u # gmapM :: Monad m => (forall d. Data d => d -> m d) -> AnyValue -> m AnyValue # gmapMp :: MonadPlus m => (forall d. Data d => d -> m d) -> AnyValue -> m AnyValue # gmapMo :: MonadPlus m => (forall d. Data d => d -> m d) -> AnyValue -> m AnyValue # | |||||
| IsString AnyValue Source # | Create a | ||||
Defined in OpenTelemetry.Internal.Common.Types Methods fromString :: String -> AnyValue # | |||||
| Generic AnyValue Source # | |||||
Defined in OpenTelemetry.Internal.Common.Types Associated Types
| |||||
| Read AnyValue Source # | |||||
| Show AnyValue Source # | |||||
| Eq AnyValue Source # | |||||
| Ord AnyValue Source # | |||||
Defined in OpenTelemetry.Internal.Common.Types | |||||
| Hashable AnyValue Source # | |||||
Defined in OpenTelemetry.Internal.Common.Types | |||||
| ToValue AnyValue Source # | |||||
| type Rep AnyValue Source # | |||||
Defined in OpenTelemetry.Internal.Common.Types type Rep AnyValue = D1 ('MetaData "AnyValue" "OpenTelemetry.Internal.Common.Types" "hs-opentelemetry-api-1.0.0.0-inplace" 'False) (((C1 ('MetaCons "TextValue" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 Text)) :+: C1 ('MetaCons "BoolValue" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 Bool))) :+: (C1 ('MetaCons "DoubleValue" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 Double)) :+: C1 ('MetaCons "IntValue" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 Int64)))) :+: ((C1 ('MetaCons "ByteStringValue" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 ByteString)) :+: C1 ('MetaCons "ArrayValue" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 [AnyValue]))) :+: (C1 ('MetaCons "HashMapValue" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (HashMap Text AnyValue))) :+: C1 ('MetaCons "NullValue" 'PrefixI 'False) (U1 :: Type -> Type)))) | |||||
class ToValue a where Source #
Convert a Haskell value to an Any value.
data Foo = Foo instance ToValue Foo where toValue Foo = TextValue Foo
Since: 0.0.1.0
Instances
| ToValue ByteString Source # | |
Defined in OpenTelemetry.Internal.Common.Types Methods toValue :: ByteString -> AnyValue Source # | |
| ToValue Int64 Source # | |
| ToValue AnyValue Source # | |
| ToValue Text Source # | |
| ToValue Bool Source # | |
| ToValue Double Source # | |
| ToValue a => ToValue [a] Source # | |
Defined in OpenTelemetry.Internal.Common.Types | |
| ToValue a => ToValue (HashMap Text a) Source # | |
data SeverityNumber Source #
Log severity level per the OTel log data model.
Spec: https://opentelemetry.io/docs/specs/otel/logs/data-model/#severity-fields
Since: 0.0.1.0
Constructors
| Trace | |
| Trace2 | |
| Trace3 | |
| Trace4 | |
| Debug | |
| Debug2 | |
| Debug3 | |
| Debug4 | |
| Info | |
| Info2 | |
| Info3 | |
| Info4 | |
| Warn | |
| Warn2 | |
| Warn3 | |
| Warn4 | |
| Error | |
| Error2 | |
| Error3 | |
| Error4 | |
| Fatal | |
| Fatal2 | |
| Fatal3 | |
| Fatal4 | |
| Unknown !Int |
Instances
| Enum SeverityNumber Source # | |
Defined in OpenTelemetry.Internal.Log.Types Methods succ :: SeverityNumber -> SeverityNumber # pred :: SeverityNumber -> SeverityNumber # toEnum :: Int -> SeverityNumber # fromEnum :: SeverityNumber -> Int # enumFrom :: SeverityNumber -> [SeverityNumber] # enumFromThen :: SeverityNumber -> SeverityNumber -> [SeverityNumber] # enumFromTo :: SeverityNumber -> SeverityNumber -> [SeverityNumber] # enumFromThenTo :: SeverityNumber -> SeverityNumber -> SeverityNumber -> [SeverityNumber] # | |
| Show SeverityNumber Source # | |
Defined in OpenTelemetry.Internal.Log.Types Methods showsPrec :: Int -> SeverityNumber -> ShowS # show :: SeverityNumber -> String # showList :: [SeverityNumber] -> ShowS # | |
| Eq SeverityNumber Source # | |
Defined in OpenTelemetry.Internal.Log.Types Methods (==) :: SeverityNumber -> SeverityNumber -> Bool # (/=) :: SeverityNumber -> SeverityNumber -> Bool # | |
| Ord SeverityNumber Source # | |
Defined in OpenTelemetry.Internal.Log.Types Methods compare :: SeverityNumber -> SeverityNumber -> Ordering # (<) :: SeverityNumber -> SeverityNumber -> Bool # (<=) :: SeverityNumber -> SeverityNumber -> Bool # (>) :: SeverityNumber -> SeverityNumber -> Bool # (>=) :: SeverityNumber -> SeverityNumber -> Bool # max :: SeverityNumber -> SeverityNumber -> SeverityNumber # min :: SeverityNumber -> SeverityNumber -> SeverityNumber # | |
toShortName :: SeverityNumber -> Maybe Text Source #
Since: 0.0.1.0
emitLogRecord :: MonadIO m => Logger -> LogRecordArguments -> m ReadWriteLogRecord Source #
Emits a LogRecord with properties specified by the passed in Logger and LogRecordArguments.
If observedTimestamp is not set in LogRecordArguments, it will default to the current timestamp.
If context is not specified in LogRecordArguments it will default to the current context.
The emitted LogRecord will be passed to any LogRecordProcessors registered on the LoggerProvider
that created the Logger, provided the record's severity meets the provider's minimum severity
threshold.
Since: 0.0.1.0
addAttribute :: (IsReadWriteLogRecord r, MonadIO m, ToValue a) => r -> Text -> a -> m () Source #
Add an attribute to a log record. Not an atomic modification.
See the OTel attribute naming conventions for guidance on choosing attribute names.
Since: 0.0.1.0
addAttributes :: (IsReadWriteLogRecord r, MonadIO m, ToValue a) => r -> HashMap Text a -> m () Source #
A convenience function related to addAttribute that adds multiple attributes to a LogRecord at the same time.
This function may be slightly more performant than repeatedly calling addAttribute.
This is not an atomic modification
Since: 0.0.1.0
logRecordGetAttributes :: (IsReadableLogRecord r, MonadIO m) => r -> m LogAttributes Source #
This can be useful for pulling data for attributes and using it to copy / otherwise use the data to further enrich instrumentation.
Since: 0.0.1.0