{-# LANGUAGE NamedFieldPuns #-}

{- |
Module      : OpenTelemetry.Internal.Log.Types
Copyright   :  (c) Ian Duncan, 2026
License     :  BSD-3
Description : Internal type definitions for the Logs signal: LoggerProvider, Logger, ReadWriteLogRecord, ImmutableLogRecord, SeverityNumber.
Stability   : experimental
-}
module OpenTelemetry.Internal.Log.Types (
  -- * UMaybe re-export for consumers of ImmutableLogRecord fields
  UMaybe (..),
  umaybe,
  toBaseMaybe,
  TracingDetails (..),
  LogRecordExporter,
  LogRecordExporterArguments (..),
  mkLogRecordExporter,
  logRecordExporterExport,
  logRecordExporterForceFlush,
  logRecordExporterShutdown,
  LogRecordProcessor (..),
  LoggerProvider (..),
  Logger (..),
  ReadWriteLogRecord,
  mkReadWriteLogRecord,
  ReadableLogRecord,
  mkReadableLogRecord,
  IsReadableLogRecord (..),
  IsReadWriteLogRecord (..),
  ImmutableLogRecord (..),
  LogRecordArguments (..),
  emptyLogRecordArguments,
  SeverityNumber (..),
  toShortName,
) where

import Control.Concurrent (MVar, newMVar, withMVar)
import Data.Function (on)
import Data.HashMap.Strict (HashMap)
import qualified Data.HashMap.Strict as H
import Data.IORef (IORef, atomicModifyIORef', newIORef, readIORef)
import Data.Text (Text)
import qualified Data.Text as T
import Data.Vector (Vector)
import OpenTelemetry.Common (Timestamp, TraceFlags)
import OpenTelemetry.Context.Types (Context)
import OpenTelemetry.Internal.Common.Types (ExportResult, FlushResult, InstrumentationLibrary, ShutdownResult)
import OpenTelemetry.Internal.Trace.Id (SpanId, TraceId)
import OpenTelemetry.Internal.UnpackedMaybe (UMaybe (..), toBaseMaybe, umaybe)
import OpenTelemetry.LogAttributes
import OpenTelemetry.Resource (MaterializedResources)


{- | See @LogRecordExporter@ for documentation

@since 0.0.1.0
-}
data LogRecordExporterArguments = LogRecordExporterArguments
  { LogRecordExporterArguments
-> Vector ReadableLogRecord -> IO ExportResult
logRecordExporterArgumentsExport :: Vector ReadableLogRecord -> IO ExportResult
  -- ^ See @logRecordExporterExport@ for documentation
  , LogRecordExporterArguments -> IO FlushResult
logRecordExporterArgumentsForceFlush :: IO FlushResult
  {- ^ See @logRecordExporterForceFlush@ for documentation.
  Spec: ForceFlush SHOULD provide a way to let the caller know
  whether it succeeded, failed or timed out.
  <https://opentelemetry.io/docs/specs/otel/logs/sdk/#logrecordexporter>
  -}
  , LogRecordExporterArguments -> IO ()
logRecordExporterArgumentsShutdown :: IO ()
  -- ^ See @logRecordExporterArgumentsShutdown@ for documentation
  }


{- | Exports log records to a telemetry backend. Thread-safe: the internal
'MVar' serializes concurrent 'logRecordExporterExport' calls.

Spec: <https://opentelemetry.io/docs/specs/otel/logs/sdk/#logrecordexporter>

@since 0.0.1.0
-}
newtype LogRecordExporter = LogRecordExporter {LogRecordExporter -> MVar LogRecordExporterArguments
unExporter :: MVar LogRecordExporterArguments}


-- | @since 0.0.1.0
mkLogRecordExporter :: LogRecordExporterArguments -> IO LogRecordExporter
mkLogRecordExporter :: LogRecordExporterArguments -> IO LogRecordExporter
mkLogRecordExporter = (MVar LogRecordExporterArguments -> LogRecordExporter)
-> IO (MVar LogRecordExporterArguments) -> IO LogRecordExporter
forall a b. (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap MVar LogRecordExporterArguments -> LogRecordExporter
LogRecordExporter (IO (MVar LogRecordExporterArguments) -> IO LogRecordExporter)
-> (LogRecordExporterArguments
    -> IO (MVar LogRecordExporterArguments))
-> LogRecordExporterArguments
-> IO LogRecordExporter
forall b c a. (b -> c) -> (a -> b) -> a -> c
. LogRecordExporterArguments -> IO (MVar LogRecordExporterArguments)
forall a. a -> IO (MVar a)
newMVar


{- | Exports a batch of ReadableLogRecords. Protocol exporters that will implement this function are typically expected to serialize
and transmit the data to the destination.

Export will never be called concurrently for the same exporter instance. Depending on the implementation the result of the export
may be returned to the Processor not in the return value of the call to Export but in a language specific way for signaling completion
of an asynchronous task. This means that while an instance of an exporter will never have it Export called concurrently it does not
mean that the task of exporting can not be done concurrently. How this is done is outside the scope of this specification.
Each implementation MUST document the concurrency characteristics the SDK requires of the exporter.

Export MUST NOT block indefinitely, there MUST be a reasonable upper limit after which the call must time out with an error result (Failure).

Concurrent requests and retry logic is the responsibility of the exporter. The default SDK’s LogRecordProcessors SHOULD NOT implement
retry logic, as the required logic is likely to depend heavily on the specific protocol and backend the logs are being sent to.
For example, the OpenTelemetry Protocol (OTLP) specification defines logic for both sending concurrent requests and retrying requests.

Result:
Success - The batch has been successfully exported. For protocol exporters this typically means that the data is sent over the wire and delivered to the destination server.
Failure - exporting failed. The batch must be dropped. For example, this can happen when the batch contains bad data and cannot be serialized.

@since 0.0.1.0
-}
logRecordExporterExport :: LogRecordExporter -> Vector ReadableLogRecord -> IO ExportResult
logRecordExporterExport :: LogRecordExporter -> Vector ReadableLogRecord -> IO ExportResult
logRecordExporterExport LogRecordExporter
exporter Vector ReadableLogRecord
lrs = MVar LogRecordExporterArguments
-> (LogRecordExporterArguments -> IO ExportResult)
-> IO ExportResult
forall a b. MVar a -> (a -> IO b) -> IO b
withMVar (LogRecordExporter -> MVar LogRecordExporterArguments
unExporter LogRecordExporter
exporter) ((LogRecordExporterArguments -> IO ExportResult)
 -> IO ExportResult)
-> (LogRecordExporterArguments -> IO ExportResult)
-> IO ExportResult
forall a b. (a -> b) -> a -> b
$ \LogRecordExporterArguments
e -> LogRecordExporterArguments
-> Vector ReadableLogRecord -> IO ExportResult
logRecordExporterArgumentsExport LogRecordExporterArguments
e Vector ReadableLogRecord
lrs


{- | This is a hint to ensure that the export of any ReadableLogRecords the exporter has received prior to the call to ForceFlush SHOULD
be completed as soon as possible, preferably before returning from this method.

ForceFlush SHOULD provide a way to let the caller know whether it succeeded, failed or timed out.

ForceFlush SHOULD only be called in cases where it is absolutely necessary, such as when using some FaaS providers that may suspend
the process after an invocation, but before the exporter exports the ReadlableLogRecords.

ForceFlush SHOULD complete or abort within some timeout. ForceFlush can be implemented as a blocking API or an asynchronous API which
notifies the caller via a callback or an event. OpenTelemetry SDK authors MAY decide if they want to make the flush timeout configurable.

@since 0.0.1.0
-}
logRecordExporterForceFlush :: LogRecordExporter -> IO FlushResult
logRecordExporterForceFlush :: LogRecordExporter -> IO FlushResult
logRecordExporterForceFlush = (MVar LogRecordExporterArguments
 -> (LogRecordExporterArguments -> IO FlushResult)
 -> IO FlushResult)
-> (LogRecordExporterArguments -> IO FlushResult)
-> MVar LogRecordExporterArguments
-> IO FlushResult
forall a b c. (a -> b -> c) -> b -> a -> c
flip MVar LogRecordExporterArguments
-> (LogRecordExporterArguments -> IO FlushResult) -> IO FlushResult
forall a b. MVar a -> (a -> IO b) -> IO b
withMVar LogRecordExporterArguments -> IO FlushResult
logRecordExporterArgumentsForceFlush (MVar LogRecordExporterArguments -> IO FlushResult)
-> (LogRecordExporter -> MVar LogRecordExporterArguments)
-> LogRecordExporter
-> IO FlushResult
forall b c a. (b -> c) -> (a -> b) -> a -> c
. LogRecordExporter -> MVar LogRecordExporterArguments
unExporter


{- | Shuts down the exporter. Called when SDK is shut down. This is an opportunity for exporter to do any cleanup required.

Shutdown SHOULD be called only once for each LogRecordExporter instance. After the call to Shutdown subsequent calls to Export are not
allowed and SHOULD return a Failure result.

Shutdown SHOULD NOT block indefinitely (e.g. if it attempts to flush the data and the destination is unavailable).
OpenTelemetry SDK authors MAY decide if they want to make the shutdown timeout configurable.

@since 0.0.1.0
-}
logRecordExporterShutdown :: LogRecordExporter -> IO ()
logRecordExporterShutdown :: LogRecordExporter -> IO ()
logRecordExporterShutdown = (MVar LogRecordExporterArguments
 -> (LogRecordExporterArguments -> IO ()) -> IO ())
-> (LogRecordExporterArguments -> IO ())
-> MVar LogRecordExporterArguments
-> IO ()
forall a b c. (a -> b -> c) -> b -> a -> c
flip MVar LogRecordExporterArguments
-> (LogRecordExporterArguments -> IO ()) -> IO ()
forall a b. MVar a -> (a -> IO b) -> IO b
withMVar LogRecordExporterArguments -> IO ()
logRecordExporterArgumentsShutdown (MVar LogRecordExporterArguments -> IO ())
-> (LogRecordExporter -> MVar LogRecordExporterArguments)
-> LogRecordExporter
-> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. LogRecordExporter -> MVar LogRecordExporterArguments
unExporter


{- | Receives callbacks when log records are emitted. Built-in processors
batch log records and pass them to exporters.

Spec: <https://opentelemetry.io/docs/specs/otel/logs/sdk/#logrecordprocessor>

@since 0.0.1.0
-}
data LogRecordProcessor = LogRecordProcessor
  { LogRecordProcessor -> ReadWriteLogRecord -> Context -> IO ()
logRecordProcessorOnEmit :: ReadWriteLogRecord -> Context -> IO ()
  {- ^ Called when a LogRecord is emitted. This method is called synchronously on the thread that emitted the LogRecord, therefore it SHOULD NOT block or throw exceptions.

  A LogRecordProcessor may freely modify logRecord for the duration of the OnEmit call. If logRecord is needed after OnEmit returns (i.e. for asynchronous processing) only reads are permitted.
  -}
  , LogRecordProcessor -> IO ShutdownResult
logRecordProcessorShutdown :: IO ShutdownResult
  {- ^ Shuts down the processor. Called when SDK is shut down. This is an opportunity for processor to do any cleanup required.

  Shutdown SHOULD be called only once for each LogRecordProcessor instance. After the call to Shutdown, subsequent calls to OnEmit are not allowed. SDKs SHOULD ignore these calls gracefully, if possible.

  Shutdown SHOULD provide a way to let the caller know whether it succeeded, failed or timed out.

  Shutdown MUST include the effects of ForceFlush.

  Shutdown SHOULD complete or abort within some timeout. Shutdown can be implemented as a blocking API or an asynchronous API which notifies the caller via a callback or an event.
  OpenTelemetry SDK authors can decide if they want to make the shutdown timeout configurable.
  -}
  , LogRecordProcessor -> IO FlushResult
logRecordProcessorForceFlush :: IO FlushResult
  {- ^ This is a hint to ensure that any tasks associated with LogRecords for which the LogRecordProcessor had already received events prior to the call to ForceFlush SHOULD be completed
  as soon as possible, preferably before returning from this method.

  In particular, if any LogRecordProcessor has any associated exporter, it SHOULD try to call the exporter’s Export with all LogRecords for which this was not already done and then invoke ForceFlush on it.
  The built-in LogRecordProcessors MUST do so. If a timeout is specified (see below), the LogRecordProcessor MUST prioritize honoring the timeout over finishing all calls. It MAY skip or abort some or all
  Export or ForceFlush calls it has made to achieve this goal.

  ForceFlush SHOULD provide a way to let the caller know whether it succeeded, failed or timed out.

  ForceFlush SHOULD only be called in cases where it is absolutely necessary, such as when using some FaaS providers that may suspend the process after an invocation, but before the LogRecordProcessor exports the emitted LogRecords.

  ForceFlush SHOULD complete or abort within some timeout. ForceFlush can be implemented as a blocking API or an asynchronous API which notifies the caller via a callback or an event. OpenTelemetry SDK authors
  can decide if they want to make the flush timeout configurable.
  -}
  }


{- | 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
-}
data LoggerProvider = LoggerProvider
  { LoggerProvider -> Vector LogRecordProcessor
loggerProviderProcessors :: Vector LogRecordProcessor
  , LoggerProvider -> MaterializedResources
loggerProviderResource :: MaterializedResources
  -- ^ Describes the source of the log, aka resource.
  , LoggerProvider -> AttributeLimits
loggerProviderAttributeLimits :: AttributeLimits
  , LoggerProvider -> IORef Bool
loggerProviderIsShutdown :: IORef Bool
  {- ^ Set to 'True' after 'shutdownLoggerProvider'. Spec: after shutdown,
  subsequent 'emitLogRecord' calls SHOULD be no-ops.
  -}
  , LoggerProvider -> Bool
loggerProviderHasProcessors :: !Bool
  -- ^ Cached at creation time. Avoids 'V.null' check on every emit.
  , LoggerProvider -> ReadWriteLogRecord -> Context -> IO ()
loggerProviderOnEmit :: ReadWriteLogRecord -> Context -> IO ()
  {- ^ Pre-composed processor callback. For 0 processors this is a no-op,
  for 1 processor it's a direct call, for N it's a fused loop.
  Avoids 'V.mapM_' + indirect call overhead on every emit.
  -}
  , LoggerProvider -> IORef (Maybe SeverityNumber)
loggerProviderMinSeverity :: IORef (Maybe SeverityNumber)
  {- ^ When 'Just sev', 'loggerIsEnabled' returns 'False' and
  'emitLogRecord' skips processor dispatch for records whose
  severity is below @sev@. Mutable at runtime via
  'setLoggerMinSeverity'. 'Nothing' means no filtering.
  -}
  , LoggerProvider -> IORef (HashMap InstrumentationLibrary Logger)
loggerProviderLoggerCache :: IORef (HashMap InstrumentationLibrary Logger)
  {- ^ Cache of 'Logger' instances per instrumentation scope. Spec: the same
  'Logger' SHOULD be returned for the same scope identity.
  -}
  }


{- | @LogRecords@ can be created from @Loggers@. @Logger@s are uniquely identified by the @libraryName@, @libraryVersion@, @schemaUrl@ fields of @InstrumentationLibrary@.
Creating two @Logger@s 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
-}
data Logger = Logger
  { Logger -> InstrumentationLibrary
loggerInstrumentationScope :: InstrumentationLibrary
  -- ^ Details about the library that the @Logger@ instruments.
  , Logger -> LoggerProvider
loggerLoggerProvider :: LoggerProvider
  -- ^ The @LoggerProvider@ that created this @Logger@. All configuration for the @Logger@ is contained in the @LoggerProvider@.
  }


{- | This is a data type that can represent logs from various sources: application log files, machine generated events, system logs, etc. [Specification outlined here.](https://opentelemetry.io/docs/specs/otel/logs/data-model/)
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
-}
data ReadWriteLogRecord = ReadWriteLogRecord Logger (IORef ImmutableLogRecord)


-- | @since 0.0.1.0
mkReadWriteLogRecord :: Logger -> ImmutableLogRecord -> IO ReadWriteLogRecord
mkReadWriteLogRecord :: Logger -> ImmutableLogRecord -> IO ReadWriteLogRecord
mkReadWriteLogRecord Logger
l = (IORef ImmutableLogRecord -> ReadWriteLogRecord)
-> IO (IORef ImmutableLogRecord) -> IO ReadWriteLogRecord
forall a b. (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Logger -> IORef ImmutableLogRecord -> ReadWriteLogRecord
ReadWriteLogRecord Logger
l) (IO (IORef ImmutableLogRecord) -> IO ReadWriteLogRecord)
-> (ImmutableLogRecord -> IO (IORef ImmutableLogRecord))
-> ImmutableLogRecord
-> IO ReadWriteLogRecord
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ImmutableLogRecord -> IO (IORef ImmutableLogRecord)
forall a. a -> IO (IORef a)
newIORef


-- | @since 0.0.1.0
data ReadableLogRecord = ReadableLogRecord
  { ReadableLogRecord -> ImmutableLogRecord
readableLogRecordSnapshot :: !ImmutableLogRecord
  , ReadableLogRecord -> InstrumentationLibrary
readableLogRecordScope :: !InstrumentationLibrary
  , ReadableLogRecord -> MaterializedResources
readableLogRecordMaterializedResource :: !MaterializedResources
  }


{- | Snapshot the current state of a 'ReadWriteLogRecord' into an immutable
'ReadableLogRecord'. Exporters that receive a 'ReadableLogRecord' are
guaranteed to see a consistent point-in-time view.

@since 0.0.1.0
-}
mkReadableLogRecord :: ReadWriteLogRecord -> IO ReadableLogRecord
mkReadableLogRecord :: ReadWriteLogRecord -> IO ReadableLogRecord
mkReadableLogRecord (ReadWriteLogRecord Logger
logger IORef ImmutableLogRecord
ref) = do
  snapshot <- IORef ImmutableLogRecord -> IO ImmutableLogRecord
forall a. IORef a -> IO a
readIORef IORef ImmutableLogRecord
ref
  pure
    ReadableLogRecord
      { readableLogRecordSnapshot = snapshot
      , readableLogRecordScope = loggerInstrumentationScope logger
      , readableLogRecordMaterializedResource = loggerProviderResource (loggerLoggerProvider logger)
      }


{- | This is a typeclass representing @LogRecord@s 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
-}
class IsReadableLogRecord r where
  -- | Reads the current state of the @LogRecord@ from its internal @IORef@. The implementation mirrors @readIORef@.
  readLogRecord :: r -> IO ImmutableLogRecord


  -- | Reads the @InstrumentationScope@ from the @Logger@ that emitted the @LogRecord@
  readLogRecordInstrumentationScope :: r -> InstrumentationLibrary


  -- | Reads the @Resource@ from the @LoggerProvider@ that emitted the @LogRecord@
  readLogRecordResource :: r -> MaterializedResources


{- | This is a typeclass representing @LogRecord@s that can be read from or written to. All @ReadWriteLogRecord@s are @ReadableLogRecord@s.

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
-}
class (IsReadableLogRecord r) => IsReadWriteLogRecord r where
  -- | Reads the attribute limits from the @LoggerProvider@ that emitted the @LogRecord@. These are needed to add more attributes.
  readLogRecordAttributeLimits :: r -> AttributeLimits


  {- | Atomically modifies the @LogRecord@ using its internal @IORef@.
  Uses @atomicModifyIORef'@ (strict) to avoid thunk buildup and ensure
  thread safety under concurrent mutation.
  -}
  modifyLogRecord :: r -> (ImmutableLogRecord -> ImmutableLogRecord) -> IO ()


  {- | Atomically modifies the @LogRecord@ and returns a value.
  Uses @atomicModifyIORef'@ (strict) for thread safety.
  -}
  atomicModifyLogRecord :: r -> (ImmutableLogRecord -> (ImmutableLogRecord, b)) -> IO b


instance IsReadableLogRecord ReadableLogRecord where
  readLogRecord :: ReadableLogRecord -> IO ImmutableLogRecord
readLogRecord = ImmutableLogRecord -> IO ImmutableLogRecord
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (ImmutableLogRecord -> IO ImmutableLogRecord)
-> (ReadableLogRecord -> ImmutableLogRecord)
-> ReadableLogRecord
-> IO ImmutableLogRecord
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ReadableLogRecord -> ImmutableLogRecord
readableLogRecordSnapshot
  readLogRecordInstrumentationScope :: ReadableLogRecord -> InstrumentationLibrary
readLogRecordInstrumentationScope = ReadableLogRecord -> InstrumentationLibrary
readableLogRecordScope
  readLogRecordResource :: ReadableLogRecord -> MaterializedResources
readLogRecordResource = ReadableLogRecord -> MaterializedResources
readableLogRecordMaterializedResource


instance IsReadableLogRecord ReadWriteLogRecord where
  readLogRecord :: ReadWriteLogRecord -> IO ImmutableLogRecord
readLogRecord (ReadWriteLogRecord Logger
_ IORef ImmutableLogRecord
ref) = IORef ImmutableLogRecord -> IO ImmutableLogRecord
forall a. IORef a -> IO a
readIORef IORef ImmutableLogRecord
ref
  readLogRecordInstrumentationScope :: ReadWriteLogRecord -> InstrumentationLibrary
readLogRecordInstrumentationScope (ReadWriteLogRecord (Logger {InstrumentationLibrary
loggerInstrumentationScope :: Logger -> InstrumentationLibrary
loggerInstrumentationScope :: InstrumentationLibrary
loggerInstrumentationScope}) IORef ImmutableLogRecord
_) = InstrumentationLibrary
loggerInstrumentationScope
  readLogRecordResource :: ReadWriteLogRecord -> MaterializedResources
readLogRecordResource (ReadWriteLogRecord Logger {loggerLoggerProvider :: Logger -> LoggerProvider
loggerLoggerProvider = LoggerProvider {MaterializedResources
loggerProviderResource :: LoggerProvider -> MaterializedResources
loggerProviderResource :: MaterializedResources
loggerProviderResource}} IORef ImmutableLogRecord
_) = MaterializedResources
loggerProviderResource


instance IsReadWriteLogRecord ReadWriteLogRecord where
  readLogRecordAttributeLimits :: ReadWriteLogRecord -> AttributeLimits
readLogRecordAttributeLimits (ReadWriteLogRecord Logger {loggerLoggerProvider :: Logger -> LoggerProvider
loggerLoggerProvider = LoggerProvider {AttributeLimits
loggerProviderAttributeLimits :: LoggerProvider -> AttributeLimits
loggerProviderAttributeLimits :: AttributeLimits
loggerProviderAttributeLimits}} IORef ImmutableLogRecord
_) = AttributeLimits
loggerProviderAttributeLimits
  modifyLogRecord :: ReadWriteLogRecord
-> (ImmutableLogRecord -> ImmutableLogRecord) -> IO ()
modifyLogRecord (ReadWriteLogRecord Logger
_ IORef ImmutableLogRecord
ref) ImmutableLogRecord -> ImmutableLogRecord
f = IORef ImmutableLogRecord
-> (ImmutableLogRecord -> (ImmutableLogRecord, ())) -> IO ()
forall a b. IORef a -> (a -> (a, b)) -> IO b
atomicModifyIORef' IORef ImmutableLogRecord
ref (\ImmutableLogRecord
ilr -> (ImmutableLogRecord -> ImmutableLogRecord
f ImmutableLogRecord
ilr, ()))
  atomicModifyLogRecord :: forall b.
ReadWriteLogRecord
-> (ImmutableLogRecord -> (ImmutableLogRecord, b)) -> IO b
atomicModifyLogRecord (ReadWriteLogRecord Logger
_ IORef ImmutableLogRecord
ref) = IORef ImmutableLogRecord
-> (ImmutableLogRecord -> (ImmutableLogRecord, b)) -> IO b
forall a b. IORef a -> (a -> (a, b)) -> IO b
atomicModifyIORef' IORef ImmutableLogRecord
ref


{- | Optional trace context attached to a log record. Uses a dedicated ADT
instead of @UMaybe (TraceId, SpanId, TraceFlags)@ so GHC can unpack all
fields flat into the constructor — no intermediate boxed tuple.

@since 0.4.0.0
-}
data TracingDetails
  = NoTracingDetails
  | TracingDetails
      {-# UNPACK #-} !TraceId
      {-# UNPACK #-} !SpanId
      {-# UNPACK #-} !TraceFlags
  deriving (TracingDetails -> TracingDetails -> Bool
(TracingDetails -> TracingDetails -> Bool)
-> (TracingDetails -> TracingDetails -> Bool) -> Eq TracingDetails
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: TracingDetails -> TracingDetails -> Bool
== :: TracingDetails -> TracingDetails -> Bool
$c/= :: TracingDetails -> TracingDetails -> Bool
/= :: TracingDetails -> TracingDetails -> Bool
Eq, Int -> TracingDetails -> ShowS
[TracingDetails] -> ShowS
TracingDetails -> String
(Int -> TracingDetails -> ShowS)
-> (TracingDetails -> String)
-> ([TracingDetails] -> ShowS)
-> Show TracingDetails
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> TracingDetails -> ShowS
showsPrec :: Int -> TracingDetails -> ShowS
$cshow :: TracingDetails -> String
show :: TracingDetails -> String
$cshowList :: [TracingDetails] -> ShowS
showList :: [TracingDetails] -> ShowS
Show)


{- | Point-in-time snapshot of a log record's fields.

Spec: <https://opentelemetry.io/docs/specs/otel/logs/data-model/>

@since 0.0.1.0
-}
data ImmutableLogRecord = ImmutableLogRecord
  { ImmutableLogRecord -> UMaybe Timestamp
logRecordTimestamp :: {-# UNPACK #-} !(UMaybe Timestamp)
  -- ^ Time when the event occurred. 'UNothing' when unknown.
  , ImmutableLogRecord -> Timestamp
logRecordObservedTimestamp :: !Timestamp
  {- ^ Time when the event was observed by the collection system. For events that originate in OpenTelemetry (e.g. using OpenTelemetry Logging SDK)
  this timestamp is typically set at the generation time and is equal to Timestamp. For events originating externally and collected by OpenTelemetry (e.g. using Collector)
  this is the time when OpenTelemetry’s code observed the event measured by the clock of the OpenTelemetry code. This field SHOULD be set once the event is observed by OpenTelemetry.

  For converting OpenTelemetry log data to formats that support only one timestamp or when receiving OpenTelemetry log data by recipients that support only one timestamp internally the following logic is recommended:
  - Use Timestamp if it is present, otherwise use ObservedTimestamp
  -}
  , ImmutableLogRecord -> TracingDetails
logRecordTracingDetails :: !TracingDetails
  {- ^ Trace context for log-trace correlation.

  - Request trace id as defined in W3C Trace Context. Can be set for logs that are part of request processing and have an assigned trace id.
  - Span id. Can be set for logs that are part of a particular processing span.
  - Trace flag as defined in W3C Trace Context specification. At the time of writing the specification defines one flag - the SAMPLED flag.
  -}
  , ImmutableLogRecord -> UMaybe Text
logRecordSeverityText :: {-# UNPACK #-} !(UMaybe Text)
  -- ^ Severity text (log level). Original string representation from the source.
  , ImmutableLogRecord -> UMaybe SeverityNumber
logRecordSeverityNumber :: {-# UNPACK #-} !(UMaybe SeverityNumber)
  {- ^ Severity number (1-24). See spec for severity ranges (TRACE/DEBUG/INFO/WARN/ERROR/FATAL).
  +-----------------------+-------------+------------------------------------------------------------------------------------------+
  | 17-20                 | ERROR       | An error event. Something went wrong.                                                    |
  +-----------------------+-------------+------------------------------------------------------------------------------------------+
  | 21-24                 | FATAL       | A fatal error such as application or system crash.                                       |
  +-----------------------+-------------+------------------------------------------------------------------------------------------+
  Smaller numerical values in each range represent less important (less severe) events. Larger numerical values in each range represent more important (more severe) events.
  For example SeverityNumber=17 describes an error that is less critical than an error with SeverityNumber=20.

  Mappings from existing logging systems and formats (or source format for short) must define how severity (or log level) of that particular format corresponds to SeverityNumber
  of this data model based on the meaning given for each range in the above table. [More Information](https://opentelemetry.io/docs/specs/otel/logs/data-model/#mapping-of-severitynumber)

  [These short names](https://opentelemetry.io/docs/specs/otel/logs/data-model/#displaying-severity) can be used to represent SeverityNumber in the UI

  In the contexts where severity participates in less-than / greater-than comparisons SeverityNumber field should be used.
  SeverityNumber can be compared to another SeverityNumber or to numbers in the 1..24 range (or to the corresponding short names).
  -}
  , ImmutableLogRecord -> AnyValue
logRecordBody :: AnyValue
  {- ^ A value containing the body of the log record. Can be for example a human-readable string message (including multi-line) describing the event in a free form or it can be a
  structured data composed of arrays and maps of other values. Body MUST support any type to preserve the semantics of structured logs emitted by the applications.
  Can vary for each occurrence of the event coming from the same source. This field is optional.

  Type any
   Value of type any can be one of the following:
   - A scalar value: number, string or boolean,
   - A byte array,
   - An array (a list) of any values,
   - A map<string, any>.
  -}
  , ImmutableLogRecord -> LogAttributes
logRecordAttributes :: LogAttributes
  {- ^ Additional information about the specific event occurrence. Unlike the Resource field, which is fixed for a particular source, Attributes can vary for each occurrence of the event coming from the same source.
  Can contain information about the request context (other than Trace Context Fields). The log attribute model MUST support any type, a superset of standard Attribute, to preserve the semantics of structured attributes
  emitted by the applications. This field is optional.
  -}
  , ImmutableLogRecord -> UMaybe Text
logRecordEventName :: {-# UNPACK #-} !(UMaybe Text)
  -- ^ Optional event name. When set, this identifies the log record as an event.
  }


{- | 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
-}
data LogRecordArguments = LogRecordArguments
  { LogRecordArguments -> Maybe Timestamp
timestamp :: Maybe Timestamp
  , LogRecordArguments -> Maybe Timestamp
observedTimestamp :: Maybe Timestamp
  , LogRecordArguments -> Maybe Context
context :: Maybe Context
  , LogRecordArguments -> Maybe Text
severityText :: Maybe Text
  , LogRecordArguments -> Maybe SeverityNumber
severityNumber :: Maybe SeverityNumber
  , LogRecordArguments -> AnyValue
body :: AnyValue
  , LogRecordArguments -> HashMap Text AnyValue
attributes :: HashMap Text AnyValue
  , LogRecordArguments -> Maybe Text
eventName :: Maybe Text
  }


-- | @since 0.0.1.0
emptyLogRecordArguments :: LogRecordArguments
emptyLogRecordArguments :: LogRecordArguments
emptyLogRecordArguments =
  LogRecordArguments
    { timestamp :: Maybe Timestamp
timestamp = Maybe Timestamp
forall a. Maybe a
Nothing
    , observedTimestamp :: Maybe Timestamp
observedTimestamp = Maybe Timestamp
forall a. Maybe a
Nothing
    , context :: Maybe Context
context = Maybe Context
forall a. Maybe a
Nothing
    , severityText :: Maybe Text
severityText = Maybe Text
forall a. Maybe a
Nothing
    , severityNumber :: Maybe SeverityNumber
severityNumber = Maybe SeverityNumber
forall a. Maybe a
Nothing
    , body :: AnyValue
body = AnyValue
NullValue
    , attributes :: HashMap Text AnyValue
attributes = HashMap Text AnyValue
forall k v. HashMap k v
H.empty
    , eventName :: Maybe Text
eventName = Maybe Text
forall a. Maybe a
Nothing
    }


{- | 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
-}
data SeverityNumber
  = 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


instance Enum SeverityNumber where
  toEnum :: Int -> SeverityNumber
toEnum Int
1 = SeverityNumber
Trace
  toEnum Int
2 = SeverityNumber
Trace2
  toEnum Int
3 = SeverityNumber
Trace3
  toEnum Int
4 = SeverityNumber
Trace4
  toEnum Int
5 = SeverityNumber
Debug
  toEnum Int
6 = SeverityNumber
Debug2
  toEnum Int
7 = SeverityNumber
Debug3
  toEnum Int
8 = SeverityNumber
Debug4
  toEnum Int
9 = SeverityNumber
Info
  toEnum Int
10 = SeverityNumber
Info2
  toEnum Int
11 = SeverityNumber
Info3
  toEnum Int
12 = SeverityNumber
Info4
  toEnum Int
13 = SeverityNumber
Warn
  toEnum Int
14 = SeverityNumber
Warn2
  toEnum Int
15 = SeverityNumber
Warn3
  toEnum Int
16 = SeverityNumber
Warn4
  toEnum Int
17 = SeverityNumber
Error
  toEnum Int
18 = SeverityNumber
Error2
  toEnum Int
19 = SeverityNumber
Error3
  toEnum Int
20 = SeverityNumber
Error4
  toEnum Int
21 = SeverityNumber
Fatal
  toEnum Int
22 = SeverityNumber
Fatal2
  toEnum Int
23 = SeverityNumber
Fatal3
  toEnum Int
24 = SeverityNumber
Fatal4
  toEnum Int
n = Int -> SeverityNumber
Unknown Int
n


  fromEnum :: SeverityNumber -> Int
fromEnum SeverityNumber
Trace = Int
1
  fromEnum SeverityNumber
Trace2 = Int
2
  fromEnum SeverityNumber
Trace3 = Int
3
  fromEnum SeverityNumber
Trace4 = Int
4
  fromEnum SeverityNumber
Debug = Int
5
  fromEnum SeverityNumber
Debug2 = Int
6
  fromEnum SeverityNumber
Debug3 = Int
7
  fromEnum SeverityNumber
Debug4 = Int
8
  fromEnum SeverityNumber
Info = Int
9
  fromEnum SeverityNumber
Info2 = Int
10
  fromEnum SeverityNumber
Info3 = Int
11
  fromEnum SeverityNumber
Info4 = Int
12
  fromEnum SeverityNumber
Warn = Int
13
  fromEnum SeverityNumber
Warn2 = Int
14
  fromEnum SeverityNumber
Warn3 = Int
15
  fromEnum SeverityNumber
Warn4 = Int
16
  fromEnum SeverityNumber
Error = Int
17
  fromEnum SeverityNumber
Error2 = Int
18
  fromEnum SeverityNumber
Error3 = Int
19
  fromEnum SeverityNumber
Error4 = Int
20
  fromEnum SeverityNumber
Fatal = Int
21
  fromEnum SeverityNumber
Fatal2 = Int
22
  fromEnum SeverityNumber
Fatal3 = Int
23
  fromEnum SeverityNumber
Fatal4 = Int
24
  fromEnum (Unknown Int
n) = Int
n


instance Eq SeverityNumber where
  == :: SeverityNumber -> SeverityNumber -> Bool
(==) = (Int -> Int -> Bool)
-> (SeverityNumber -> Int)
-> SeverityNumber
-> SeverityNumber
-> Bool
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
on Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
(==) SeverityNumber -> Int
forall a. Enum a => a -> Int
fromEnum


instance Ord SeverityNumber where
  compare :: SeverityNumber -> SeverityNumber -> Ordering
compare = (Int -> Int -> Ordering)
-> (SeverityNumber -> Int)
-> SeverityNumber
-> SeverityNumber
-> Ordering
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
on Int -> Int -> Ordering
forall a. Ord a => a -> a -> Ordering
compare SeverityNumber -> Int
forall a. Enum a => a -> Int
fromEnum


-- | @since 0.0.1.0
toShortName :: SeverityNumber -> Maybe Text
toShortName :: SeverityNumber -> Maybe Text
toShortName SeverityNumber
Trace = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"TRACE"
toShortName SeverityNumber
Trace2 = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"TRACE2"
toShortName SeverityNumber
Trace3 = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"TRACE3"
toShortName SeverityNumber
Trace4 = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"TRACE4"
toShortName SeverityNumber
Debug = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"DEBUG"
toShortName SeverityNumber
Debug2 = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"DEBUG2"
toShortName SeverityNumber
Debug3 = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"DEBUG3"
toShortName SeverityNumber
Debug4 = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"DEBUG4"
toShortName SeverityNumber
Info = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"INFO"
toShortName SeverityNumber
Info2 = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"INFO2"
toShortName SeverityNumber
Info3 = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"INFO3"
toShortName SeverityNumber
Info4 = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"INFO4"
toShortName SeverityNumber
Warn = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"WARN"
toShortName SeverityNumber
Warn2 = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"WARN2"
toShortName SeverityNumber
Warn3 = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"WARN3"
toShortName SeverityNumber
Warn4 = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"WARN4"
toShortName SeverityNumber
Error = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"ERROR"
toShortName SeverityNumber
Error2 = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"ERROR2"
toShortName SeverityNumber
Error3 = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"ERROR3"
toShortName SeverityNumber
Error4 = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"ERROR4"
toShortName SeverityNumber
Fatal = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"FATAL"
toShortName SeverityNumber
Fatal2 = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"FATAL2"
toShortName SeverityNumber
Fatal3 = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"FATAL3"
toShortName SeverityNumber
Fatal4 = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"FATAL4"
toShortName (Unknown Int
_) = Maybe Text
forall a. Maybe a
Nothing


instance Show SeverityNumber where
  show :: SeverityNumber -> String
show SeverityNumber
s = case SeverityNumber -> Maybe Text
toShortName SeverityNumber
s of
    Just Text
name -> Text -> String
T.unpack Text
name
    Maybe Text
Nothing -> String
"SeverityNumber " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> Int -> String
forall a. Show a => a -> String
show (SeverityNumber -> Int
forall a. Enum a => a -> Int
fromEnum SeverityNumber
s)