packages feed

shibuya-core-0.1.0.0: src/Shibuya/Telemetry/Semantic.hs

-- | Semantic conventions for Shibuya OpenTelemetry instrumentation.
-- Provides span names, attribute keys, and helpers following OTel conventions.
module Shibuya.Telemetry.Semantic
  ( -- * Span Names
    processMessageSpanName,
    ingestSpanName,

    -- * Attribute Keys (OTel Messaging Conventions)
    attrMessagingSystem,
    attrMessagingMessageId,
    attrMessagingDestinationName,
    attrMessagingDestinationPartitionId,

    -- * Attribute Keys (Shibuya-specific)
    attrShibuyaProcessorId,
    attrShibuyaInflightCount,
    attrShibuyaInflightMax,
    attrShibuyaAckDecision,

    -- * Event Names
    eventHandlerStarted,
    eventHandlerCompleted,
    eventHandlerException,
    eventAckDecision,

    -- * SpanArguments Helpers
    consumerSpanArgs,
    internalSpanArgs,

    -- * NewEvent Helper
    mkEvent,
  )
where

import Data.HashMap.Strict qualified as HashMap
import Data.Text (Text)
import OpenTelemetry.Attributes (Attribute)
import OpenTelemetry.Trace.Core
  ( NewEvent (..),
    SpanArguments (..),
    SpanKind (..),
  )

--------------------------------------------------------------------------------
-- Span Names
--------------------------------------------------------------------------------

-- | Span name for processing a single message.
processMessageSpanName :: Text
processMessageSpanName = "shibuya.process.message"

-- | Span name for the ingester lifecycle.
ingestSpanName :: Text
ingestSpanName = "shibuya.ingest"

--------------------------------------------------------------------------------
-- Attribute Keys (OTel Messaging Semantic Conventions)
-- See: https://opentelemetry.io/docs/specs/semconv/messaging/messaging-spans/
--------------------------------------------------------------------------------

-- | The messaging system identifier.
attrMessagingSystem :: Text
attrMessagingSystem = "messaging.system"

-- | The message identifier.
attrMessagingMessageId :: Text
attrMessagingMessageId = "messaging.message.id"

-- | The destination (queue/topic) name.
attrMessagingDestinationName :: Text
attrMessagingDestinationName = "messaging.destination.name"

-- | The partition identifier.
attrMessagingDestinationPartitionId :: Text
attrMessagingDestinationPartitionId = "messaging.destination.partition.id"

--------------------------------------------------------------------------------
-- Attribute Keys (Shibuya-specific)
--------------------------------------------------------------------------------

-- | The processor identifier.
attrShibuyaProcessorId :: Text
attrShibuyaProcessorId = "shibuya.processor.id"

-- | Current number of in-flight messages.
attrShibuyaInflightCount :: Text
attrShibuyaInflightCount = "shibuya.inflight.count"

-- | Maximum concurrency limit.
attrShibuyaInflightMax :: Text
attrShibuyaInflightMax = "shibuya.inflight.max"

-- | The ack decision made by the handler.
attrShibuyaAckDecision :: Text
attrShibuyaAckDecision = "shibuya.ack.decision"

--------------------------------------------------------------------------------
-- Event Names
--------------------------------------------------------------------------------

-- | Event recorded when handler execution starts.
eventHandlerStarted :: Text
eventHandlerStarted = "handler.started"

-- | Event recorded when handler execution completes successfully.
eventHandlerCompleted :: Text
eventHandlerCompleted = "handler.completed"

-- | Event recorded when handler throws an exception.
eventHandlerException :: Text
eventHandlerException = "handler.exception"

-- | Event recorded when ack decision is made.
eventAckDecision :: Text
eventAckDecision = "ack.decision"

--------------------------------------------------------------------------------
-- SpanArguments Helpers
--------------------------------------------------------------------------------

-- | SpanArguments for message consumption (Consumer kind).
consumerSpanArgs :: SpanArguments
consumerSpanArgs =
  SpanArguments
    { kind = Consumer,
      attributes = HashMap.empty,
      links = [],
      startTime = Nothing
    }

-- | SpanArguments for internal operations (Internal kind).
internalSpanArgs :: SpanArguments
internalSpanArgs =
  SpanArguments
    { kind = Internal,
      attributes = HashMap.empty,
      links = [],
      startTime = Nothing
    }

--------------------------------------------------------------------------------
-- NewEvent Helper
--------------------------------------------------------------------------------

-- | Create a NewEvent with the given name and attributes.
-- Use 'toAttribute' to convert values to Attribute.
--
-- Example:
--
-- @
-- mkEvent "handler.completed"
--   [ ("duration_ms", toAttribute (42 :: Int))
--   , ("status", toAttribute ("ok" :: Text))
--   ]
-- @
mkEvent :: Text -> [(Text, Attribute)] -> NewEvent
mkEvent name attrs =
  NewEvent
    { newEventName = name,
      newEventAttributes = HashMap.fromList attrs,
      newEventTimestamp = Nothing
    }