{- | The @ecluse.*@ metric catalogue and its __bounded-label discipline__.

An inline proxy sees thousands of distinct packages, so the failure mode for metrics
is a __series explosion__: a single high-cardinality label (a package name, a version,
a denial message) multiplied across every package turns a handful of series into
millions. This module is the structural defence. It defines the catalogue of metric
__names__ and, crucially, the __closed set of label types__ a metric may carry -- every
one a small, fixed-domain enum.

== Bounded labels

The label vocabulary is a closed sum, 'Label', whose every constructor pairs a
bounded-domain key with a bounded value. High-cardinality identifiers -- @package@,
@version@, @scope@, and a denial @message@ -- have __no constructor here at all__, so
they cannot be made into a metric label: the type system forbids it. They live on
spans and the structured log line ("Ecluse.Log") instead, which is where a specific
decision is debugged. The one operator-bounded label is @rule@ (a rule's configured
name): a deployment defines a small, fixed set of rules, so it is bounded by
configuration rather than by an enum, and is the sole label carrying free text.

'renderLabel' projects a 'Label' to its @(key, value)@ wire pair, and 'metricAttributes'
materialises a label list into the OpenTelemetry 'Attributes' an instrument is recorded
with. The catalogue and the cardinality rule are described in
@docs\/architecture\/observability.md@.
-}
module Ecluse.Core.Telemetry.Metrics (
    -- * The metric-name catalogue
    MetricName (..),
    metricName,
    allMetricNames,

    -- * Label keys (the closed set)
    LabelKey (..),
    labelKeyName,
    allLabelKeys,
    highCardinalityKeys,

    -- * Bounded label values
    Decision (..),
    ReasonClass (..),
    Upstream (..),
    StatusClass (..),
    statusClassOf,
    Provider (..),
    Cause (..),
    Tier (..),
    CacheResult (..),
    MirrorResult (..),
    CredentialResult (..),
    BreakerSource (..),

    -- * Breaker state (a bounded gauge value, not a label)
    BreakerState (..),
    breakerStateCode,

    -- * Labels
    Label (..),
    labelKey,
    renderLabel,

    -- * Attribute construction
    metricAttributes,
) where

-- relude's prelude exports a Bounded/Enum-based `universe`; hide it so the
-- Generic-derived `Data.Universe.Class.universe` is the one in scope here.
import Prelude hiding (universe)

import OpenTelemetry.Attributes (
    Attributes,
    addAttributesFromBuilder,
    attr,
    defaultAttributeLimits,
    emptyAttributes,
 )

import Data.Universe.Class (Universe (..))
import Data.Universe.Generic (universeGeneric)

import Ecluse.Core.Ecosystem (Ecosystem, ecosystemName)

{- | The catalogue of metric instruments Écluse emits: the @ecluse.*@ domain signals
plus the OpenTelemetry HTTP server semantic convention. Each maps to its wire name
through 'metricName'; a typed enum so the catalogue is enumerable (and asserted whole
in the tests) rather than a scatter of string literals.

Queue backlog and DLQ depth are deliberately absent -- those are cloud-native metrics
(CloudWatch, Cloud Monitoring), not signals Écluse re-emits. Advisory-sync metrics are
deferred until the advisory subsystem exists.
-}
data MetricName
    = -- | @http.server.request.duration@ -- server request latency (histogram).
      HttpServerRequestDuration
    | -- | @ecluse.serve.decision@ -- admit\/deny\/unavailable (counter).
      ServeDecision
    | -- | @ecluse.rule.denials@ -- rule denials by rule and reason class (counter).
      RuleDenials
    | -- | @ecluse.rule.eval.duration@ -- rule-evaluation latency by tier (histogram).
      RuleEvalDuration
    | -- | @ecluse.rule.effectful.failures@ -- effectful-rule failures (counter).
      RuleEffectfulFailures
    | -- | @ecluse.rule.breaker.state@ -- effectful\/mint breaker state by source (gauge).
      RuleBreakerState
    | -- | @ecluse.serve.admission.in_flight@ -- in-flight metadata parses (up-down counter).
      ServeAdmissionInFlight
    | -- | @ecluse.serve.admission.queued@ -- admissions that waited for a slot (counter).
      ServeAdmissionQueued
    | -- | @ecluse.upstream.fetch.duration@ -- upstream fetch latency (histogram).
      UpstreamFetchDuration
    | -- | @ecluse.upstream.fetch.errors@ -- upstream fetch errors (counter).
      UpstreamFetchErrors
    | -- | @ecluse.metadata_cache.requests@ -- metadata-cache hit\/miss (counter).
      MetadataCacheRequests
    | -- | @ecluse.metadata_cache.entries@ -- metadata-cache occupancy (gauge).
      MetadataCacheEntries
    | -- | @ecluse.metadata_cache.resident_bytes@: full-packument cache resident bytes (gauge).
      MetadataCacheResidentBytes
    | -- | @ecluse.metadata_cache.version.resident_bytes@: single-version cache resident bytes (gauge).
      SingleVersionCacheResidentBytes
    | -- | @ecluse.metadata_cache.assembled.resident_bytes@: assembled-representation store resident bytes (gauge).
      AssembledCacheResidentBytes
    | -- | @ecluse.mirror.enqueued@ -- mirror jobs enqueued (counter).
      MirrorEnqueued
    | -- | @ecluse.mirror.enqueue.failures@ -- mirror enqueue failures (counter).
      MirrorEnqueueFailures
    | -- | @ecluse.mirror.jobs.processed@ -- mirror jobs processed by result (counter).
      MirrorJobsProcessed
    | -- | @ecluse.mirror.publish.duration@ -- mirror publish latency (histogram).
      MirrorPublishDuration
    | -- | @ecluse.credential.refresh@ -- credential refreshes by result and provider (counter).
      CredentialRefresh
    | -- | @ecluse.credential.token.ttl.seconds@ -- remaining token lifetime by provider (gauge).
      CredentialTokenTtlSeconds
    deriving stock (MetricName -> MetricName -> Bool
(MetricName -> MetricName -> Bool)
-> (MetricName -> MetricName -> Bool) -> Eq MetricName
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: MetricName -> MetricName -> Bool
== :: MetricName -> MetricName -> Bool
$c/= :: MetricName -> MetricName -> Bool
/= :: MetricName -> MetricName -> Bool
Eq, (forall x. MetricName -> Rep MetricName x)
-> (forall x. Rep MetricName x -> MetricName) -> Generic MetricName
forall x. Rep MetricName x -> MetricName
forall x. MetricName -> Rep MetricName x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. MetricName -> Rep MetricName x
from :: forall x. MetricName -> Rep MetricName x
$cto :: forall x. Rep MetricName x -> MetricName
to :: forall x. Rep MetricName x -> MetricName
Generic, Eq MetricName
Eq MetricName =>
(MetricName -> MetricName -> Ordering)
-> (MetricName -> MetricName -> Bool)
-> (MetricName -> MetricName -> Bool)
-> (MetricName -> MetricName -> Bool)
-> (MetricName -> MetricName -> Bool)
-> (MetricName -> MetricName -> MetricName)
-> (MetricName -> MetricName -> MetricName)
-> Ord MetricName
MetricName -> MetricName -> Bool
MetricName -> MetricName -> Ordering
MetricName -> MetricName -> MetricName
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: MetricName -> MetricName -> Ordering
compare :: MetricName -> MetricName -> Ordering
$c< :: MetricName -> MetricName -> Bool
< :: MetricName -> MetricName -> Bool
$c<= :: MetricName -> MetricName -> Bool
<= :: MetricName -> MetricName -> Bool
$c> :: MetricName -> MetricName -> Bool
> :: MetricName -> MetricName -> Bool
$c>= :: MetricName -> MetricName -> Bool
>= :: MetricName -> MetricName -> Bool
$cmax :: MetricName -> MetricName -> MetricName
max :: MetricName -> MetricName -> MetricName
$cmin :: MetricName -> MetricName -> MetricName
min :: MetricName -> MetricName -> MetricName
Ord, Int -> MetricName -> ShowS
[MetricName] -> ShowS
MetricName -> String
(Int -> MetricName -> ShowS)
-> (MetricName -> String)
-> ([MetricName] -> ShowS)
-> Show MetricName
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> MetricName -> ShowS
showsPrec :: Int -> MetricName -> ShowS
$cshow :: MetricName -> String
show :: MetricName -> String
$cshowList :: [MetricName] -> ShowS
showList :: [MetricName] -> ShowS
Show)

instance Universe MetricName where universe :: [MetricName]
universe = [MetricName]
forall a. (Generic a, GUniverse (Rep a)) => [a]
universeGeneric

-- | The wire name of a 'MetricName'.
metricName :: MetricName -> Text
metricName :: MetricName -> Text
metricName = \case
    MetricName
HttpServerRequestDuration -> Text
"http.server.request.duration"
    MetricName
ServeDecision -> Text
"ecluse.serve.decision"
    MetricName
RuleDenials -> Text
"ecluse.rule.denials"
    MetricName
RuleEvalDuration -> Text
"ecluse.rule.eval.duration"
    MetricName
RuleEffectfulFailures -> Text
"ecluse.rule.effectful.failures"
    MetricName
RuleBreakerState -> Text
"ecluse.rule.breaker.state"
    MetricName
ServeAdmissionInFlight -> Text
"ecluse.serve.admission.in_flight"
    MetricName
ServeAdmissionQueued -> Text
"ecluse.serve.admission.queued"
    MetricName
UpstreamFetchDuration -> Text
"ecluse.upstream.fetch.duration"
    MetricName
UpstreamFetchErrors -> Text
"ecluse.upstream.fetch.errors"
    MetricName
MetadataCacheRequests -> Text
"ecluse.metadata_cache.requests"
    MetricName
MetadataCacheEntries -> Text
"ecluse.metadata_cache.entries"
    MetricName
MetadataCacheResidentBytes -> Text
"ecluse.metadata_cache.resident_bytes"
    MetricName
SingleVersionCacheResidentBytes -> Text
"ecluse.metadata_cache.version.resident_bytes"
    MetricName
AssembledCacheResidentBytes -> Text
"ecluse.metadata_cache.assembled.resident_bytes"
    MetricName
MirrorEnqueued -> Text
"ecluse.mirror.enqueued"
    MetricName
MirrorEnqueueFailures -> Text
"ecluse.mirror.enqueue.failures"
    MetricName
MirrorJobsProcessed -> Text
"ecluse.mirror.jobs.processed"
    MetricName
MirrorPublishDuration -> Text
"ecluse.mirror.publish.duration"
    MetricName
CredentialRefresh -> Text
"ecluse.credential.refresh"
    MetricName
CredentialTokenTtlSeconds -> Text
"ecluse.credential.token.ttl.seconds"

-- | Every metric in the catalogue (the Generic-derived 'Universe' enumeration).
allMetricNames :: [MetricName]
allMetricNames :: [MetricName]
allMetricNames = [MetricName]
forall a. Universe a => [a]
universe

{- | The closed set of metric label keys. Every label Écluse attaches is one of these
bounded-domain keys. High-cardinality identifiers (@package@, @version@, @scope@, a
denial @message@) are deliberately __absent__ -- see 'highCardinalityKeys' -- so they
can never become a metric label.
-}
data LabelKey
    = KeyDecision
    | KeyReasonClass
    | KeyRule
    | KeyEcosystem
    | KeyMount
    | KeyUpstream
    | KeyStatusClass
    | KeyResult
    | KeyProvider
    | KeyCause
    | KeyBreakerSource
    | KeyTier
    deriving stock (LabelKey -> LabelKey -> Bool
(LabelKey -> LabelKey -> Bool)
-> (LabelKey -> LabelKey -> Bool) -> Eq LabelKey
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: LabelKey -> LabelKey -> Bool
== :: LabelKey -> LabelKey -> Bool
$c/= :: LabelKey -> LabelKey -> Bool
/= :: LabelKey -> LabelKey -> Bool
Eq, (forall x. LabelKey -> Rep LabelKey x)
-> (forall x. Rep LabelKey x -> LabelKey) -> Generic LabelKey
forall x. Rep LabelKey x -> LabelKey
forall x. LabelKey -> Rep LabelKey x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. LabelKey -> Rep LabelKey x
from :: forall x. LabelKey -> Rep LabelKey x
$cto :: forall x. Rep LabelKey x -> LabelKey
to :: forall x. Rep LabelKey x -> LabelKey
Generic, Eq LabelKey
Eq LabelKey =>
(LabelKey -> LabelKey -> Ordering)
-> (LabelKey -> LabelKey -> Bool)
-> (LabelKey -> LabelKey -> Bool)
-> (LabelKey -> LabelKey -> Bool)
-> (LabelKey -> LabelKey -> Bool)
-> (LabelKey -> LabelKey -> LabelKey)
-> (LabelKey -> LabelKey -> LabelKey)
-> Ord LabelKey
LabelKey -> LabelKey -> Bool
LabelKey -> LabelKey -> Ordering
LabelKey -> LabelKey -> LabelKey
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: LabelKey -> LabelKey -> Ordering
compare :: LabelKey -> LabelKey -> Ordering
$c< :: LabelKey -> LabelKey -> Bool
< :: LabelKey -> LabelKey -> Bool
$c<= :: LabelKey -> LabelKey -> Bool
<= :: LabelKey -> LabelKey -> Bool
$c> :: LabelKey -> LabelKey -> Bool
> :: LabelKey -> LabelKey -> Bool
$c>= :: LabelKey -> LabelKey -> Bool
>= :: LabelKey -> LabelKey -> Bool
$cmax :: LabelKey -> LabelKey -> LabelKey
max :: LabelKey -> LabelKey -> LabelKey
$cmin :: LabelKey -> LabelKey -> LabelKey
min :: LabelKey -> LabelKey -> LabelKey
Ord, Int -> LabelKey -> ShowS
[LabelKey] -> ShowS
LabelKey -> String
(Int -> LabelKey -> ShowS)
-> (LabelKey -> String) -> ([LabelKey] -> ShowS) -> Show LabelKey
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> LabelKey -> ShowS
showsPrec :: Int -> LabelKey -> ShowS
$cshow :: LabelKey -> String
show :: LabelKey -> String
$cshowList :: [LabelKey] -> ShowS
showList :: [LabelKey] -> ShowS
Show)

instance Universe LabelKey where universe :: [LabelKey]
universe = [LabelKey]
forall a. (Generic a, GUniverse (Rep a)) => [a]
universeGeneric

-- | The wire name of a 'LabelKey'.
labelKeyName :: LabelKey -> Text
labelKeyName :: LabelKey -> Text
labelKeyName = \case
    LabelKey
KeyDecision -> Text
"decision"
    LabelKey
KeyReasonClass -> Text
"reason_class"
    LabelKey
KeyRule -> Text
"rule"
    LabelKey
KeyEcosystem -> Text
"ecosystem"
    LabelKey
KeyMount -> Text
"mount"
    LabelKey
KeyUpstream -> Text
"upstream"
    LabelKey
KeyStatusClass -> Text
"status_class"
    LabelKey
KeyResult -> Text
"result"
    LabelKey
KeyProvider -> Text
"provider"
    LabelKey
KeyCause -> Text
"cause"
    LabelKey
KeyBreakerSource -> Text
"source"
    LabelKey
KeyTier -> Text
"tier"

-- | Every label key in the closed set.
allLabelKeys :: [LabelKey]
allLabelKeys :: [LabelKey]
allLabelKeys = [LabelKey]
forall a. Universe a => [a]
universe

{- | The high-cardinality identifiers that must __never__ be metric labels: they live
on spans and the structured log line instead. The label-domain guard asserts none of
these is a 'LabelKey' wire name; there is, by construction, no 'Label' that produces one.
-}
highCardinalityKeys :: [Text]
highCardinalityKeys :: [Text]
highCardinalityKeys = [Text
"package", Text
"version", Text
"scope", Text
"message"]

-- | The serve decision (@ecluse.serve.decision@).
data Decision = Admit | Deny | Unavailable
    deriving stock (Decision -> Decision -> Bool
(Decision -> Decision -> Bool)
-> (Decision -> Decision -> Bool) -> Eq Decision
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Decision -> Decision -> Bool
== :: Decision -> Decision -> Bool
$c/= :: Decision -> Decision -> Bool
/= :: Decision -> Decision -> Bool
Eq, (forall x. Decision -> Rep Decision x)
-> (forall x. Rep Decision x -> Decision) -> Generic Decision
forall x. Rep Decision x -> Decision
forall x. Decision -> Rep Decision x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. Decision -> Rep Decision x
from :: forall x. Decision -> Rep Decision x
$cto :: forall x. Rep Decision x -> Decision
to :: forall x. Rep Decision x -> Decision
Generic, Int -> Decision -> ShowS
[Decision] -> ShowS
Decision -> String
(Int -> Decision -> ShowS)
-> (Decision -> String) -> ([Decision] -> ShowS) -> Show Decision
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Decision -> ShowS
showsPrec :: Int -> Decision -> ShowS
$cshow :: Decision -> String
show :: Decision -> String
$cshowList :: [Decision] -> ShowS
showList :: [Decision] -> ShowS
Show)

instance Universe Decision where universe :: [Decision]
universe = [Decision]
forall a. (Generic a, GUniverse (Rep a)) => [a]
universeGeneric

{- | The bucketed class of a denial reason -- a bounded summary of
"Ecluse.Core.Server.Response.RejectReason", __not__ the rule name or the message (those are
high-cardinality and stay on the log line).
-}
data ReasonClass = ReasonPolicy | ReasonMissingIntegrity | ReasonUnavailable | ReasonLimit
    deriving stock (ReasonClass -> ReasonClass -> Bool
(ReasonClass -> ReasonClass -> Bool)
-> (ReasonClass -> ReasonClass -> Bool) -> Eq ReasonClass
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: ReasonClass -> ReasonClass -> Bool
== :: ReasonClass -> ReasonClass -> Bool
$c/= :: ReasonClass -> ReasonClass -> Bool
/= :: ReasonClass -> ReasonClass -> Bool
Eq, (forall x. ReasonClass -> Rep ReasonClass x)
-> (forall x. Rep ReasonClass x -> ReasonClass)
-> Generic ReasonClass
forall x. Rep ReasonClass x -> ReasonClass
forall x. ReasonClass -> Rep ReasonClass x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. ReasonClass -> Rep ReasonClass x
from :: forall x. ReasonClass -> Rep ReasonClass x
$cto :: forall x. Rep ReasonClass x -> ReasonClass
to :: forall x. Rep ReasonClass x -> ReasonClass
Generic, Int -> ReasonClass -> ShowS
[ReasonClass] -> ShowS
ReasonClass -> String
(Int -> ReasonClass -> ShowS)
-> (ReasonClass -> String)
-> ([ReasonClass] -> ShowS)
-> Show ReasonClass
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> ReasonClass -> ShowS
showsPrec :: Int -> ReasonClass -> ShowS
$cshow :: ReasonClass -> String
show :: ReasonClass -> String
$cshowList :: [ReasonClass] -> ShowS
showList :: [ReasonClass] -> ShowS
Show)

instance Universe ReasonClass where universe :: [ReasonClass]
universe = [ReasonClass]
forall a. (Generic a, GUniverse (Rep a)) => [a]
universeGeneric

-- | Which upstream a data-plane fetch targeted.
data Upstream = Private | Public
    deriving stock (Upstream -> Upstream -> Bool
(Upstream -> Upstream -> Bool)
-> (Upstream -> Upstream -> Bool) -> Eq Upstream
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Upstream -> Upstream -> Bool
== :: Upstream -> Upstream -> Bool
$c/= :: Upstream -> Upstream -> Bool
/= :: Upstream -> Upstream -> Bool
Eq, (forall x. Upstream -> Rep Upstream x)
-> (forall x. Rep Upstream x -> Upstream) -> Generic Upstream
forall x. Rep Upstream x -> Upstream
forall x. Upstream -> Rep Upstream x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. Upstream -> Rep Upstream x
from :: forall x. Upstream -> Rep Upstream x
$cto :: forall x. Rep Upstream x -> Upstream
to :: forall x. Rep Upstream x -> Upstream
Generic, Int -> Upstream -> ShowS
[Upstream] -> ShowS
Upstream -> String
(Int -> Upstream -> ShowS)
-> (Upstream -> String) -> ([Upstream] -> ShowS) -> Show Upstream
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Upstream -> ShowS
showsPrec :: Int -> Upstream -> ShowS
$cshow :: Upstream -> String
show :: Upstream -> String
$cshowList :: [Upstream] -> ShowS
showList :: [Upstream] -> ShowS
Show)

instance Universe Upstream where universe :: [Upstream]
universe = [Upstream]
forall a. (Generic a, GUniverse (Rep a)) => [a]
universeGeneric

-- | The HTTP status class of an upstream response (the bounded summary of the code).
data StatusClass = Status2xx | Status3xx | Status4xx | Status5xx | StatusOther
    deriving stock (StatusClass -> StatusClass -> Bool
(StatusClass -> StatusClass -> Bool)
-> (StatusClass -> StatusClass -> Bool) -> Eq StatusClass
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: StatusClass -> StatusClass -> Bool
== :: StatusClass -> StatusClass -> Bool
$c/= :: StatusClass -> StatusClass -> Bool
/= :: StatusClass -> StatusClass -> Bool
Eq, (forall x. StatusClass -> Rep StatusClass x)
-> (forall x. Rep StatusClass x -> StatusClass)
-> Generic StatusClass
forall x. Rep StatusClass x -> StatusClass
forall x. StatusClass -> Rep StatusClass x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. StatusClass -> Rep StatusClass x
from :: forall x. StatusClass -> Rep StatusClass x
$cto :: forall x. Rep StatusClass x -> StatusClass
to :: forall x. Rep StatusClass x -> StatusClass
Generic, Int -> StatusClass -> ShowS
[StatusClass] -> ShowS
StatusClass -> String
(Int -> StatusClass -> ShowS)
-> (StatusClass -> String)
-> ([StatusClass] -> ShowS)
-> Show StatusClass
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> StatusClass -> ShowS
showsPrec :: Int -> StatusClass -> ShowS
$cshow :: StatusClass -> String
show :: StatusClass -> String
$cshowList :: [StatusClass] -> ShowS
showList :: [StatusClass] -> ShowS
Show)

instance Universe StatusClass where universe :: [StatusClass]
universe = [StatusClass]
forall a. (Generic a, GUniverse (Rep a)) => [a]
universeGeneric

-- | The outbound-credential provider a refresh\/ttl signal concerns.
data Provider = CodeArtifact | Static | Adc
    deriving stock (Provider -> Provider -> Bool
(Provider -> Provider -> Bool)
-> (Provider -> Provider -> Bool) -> Eq Provider
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Provider -> Provider -> Bool
== :: Provider -> Provider -> Bool
$c/= :: Provider -> Provider -> Bool
/= :: Provider -> Provider -> Bool
Eq, (forall x. Provider -> Rep Provider x)
-> (forall x. Rep Provider x -> Provider) -> Generic Provider
forall x. Rep Provider x -> Provider
forall x. Provider -> Rep Provider x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. Provider -> Rep Provider x
from :: forall x. Provider -> Rep Provider x
$cto :: forall x. Rep Provider x -> Provider
to :: forall x. Rep Provider x -> Provider
Generic, Int -> Provider -> ShowS
[Provider] -> ShowS
Provider -> String
(Int -> Provider -> ShowS)
-> (Provider -> String) -> ([Provider] -> ShowS) -> Show Provider
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Provider -> ShowS
showsPrec :: Int -> Provider -> ShowS
$cshow :: Provider -> String
show :: Provider -> String
$cshowList :: [Provider] -> ShowS
showList :: [Provider] -> ShowS
Show)

instance Universe Provider where universe :: [Provider]
universe = [Provider]
forall a. (Generic a, GUniverse (Rep a)) => [a]
universeGeneric

-- | A bounded error class for a failure signal (never the exception text).
data Cause = Timeout | Connection | Decode | UpstreamStatus | OtherCause
    deriving stock (Cause -> Cause -> Bool
(Cause -> Cause -> Bool) -> (Cause -> Cause -> Bool) -> Eq Cause
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Cause -> Cause -> Bool
== :: Cause -> Cause -> Bool
$c/= :: Cause -> Cause -> Bool
/= :: Cause -> Cause -> Bool
Eq, (forall x. Cause -> Rep Cause x)
-> (forall x. Rep Cause x -> Cause) -> Generic Cause
forall x. Rep Cause x -> Cause
forall x. Cause -> Rep Cause x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. Cause -> Rep Cause x
from :: forall x. Cause -> Rep Cause x
$cto :: forall x. Rep Cause x -> Cause
to :: forall x. Rep Cause x -> Cause
Generic, Int -> Cause -> ShowS
[Cause] -> ShowS
Cause -> String
(Int -> Cause -> ShowS)
-> (Cause -> String) -> ([Cause] -> ShowS) -> Show Cause
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Cause -> ShowS
showsPrec :: Int -> Cause -> ShowS
$cshow :: Cause -> String
show :: Cause -> String
$cshowList :: [Cause] -> ShowS
showList :: [Cause] -> ShowS
Show)

instance Universe Cause where universe :: [Cause]
universe = [Cause]
forall a. (Generic a, GUniverse (Rep a)) => [a]
universeGeneric

-- | The rule-evaluation tier a duration is measured at.
data Tier = Structural | Effectful
    deriving stock (Tier -> Tier -> Bool
(Tier -> Tier -> Bool) -> (Tier -> Tier -> Bool) -> Eq Tier
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Tier -> Tier -> Bool
== :: Tier -> Tier -> Bool
$c/= :: Tier -> Tier -> Bool
/= :: Tier -> Tier -> Bool
Eq, (forall x. Tier -> Rep Tier x)
-> (forall x. Rep Tier x -> Tier) -> Generic Tier
forall x. Rep Tier x -> Tier
forall x. Tier -> Rep Tier x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. Tier -> Rep Tier x
from :: forall x. Tier -> Rep Tier x
$cto :: forall x. Rep Tier x -> Tier
to :: forall x. Rep Tier x -> Tier
Generic, Int -> Tier -> ShowS
[Tier] -> ShowS
Tier -> String
(Int -> Tier -> ShowS)
-> (Tier -> String) -> ([Tier] -> ShowS) -> Show Tier
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Tier -> ShowS
showsPrec :: Int -> Tier -> ShowS
$cshow :: Tier -> String
show :: Tier -> String
$cshowList :: [Tier] -> ShowS
showList :: [Tier] -> ShowS
Show)

instance Universe Tier where universe :: [Tier]
universe = [Tier]
forall a. (Generic a, GUniverse (Rep a)) => [a]
universeGeneric

-- | A metadata-cache lookup result.
data CacheResult = Hit | Miss
    deriving stock (CacheResult -> CacheResult -> Bool
(CacheResult -> CacheResult -> Bool)
-> (CacheResult -> CacheResult -> Bool) -> Eq CacheResult
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: CacheResult -> CacheResult -> Bool
== :: CacheResult -> CacheResult -> Bool
$c/= :: CacheResult -> CacheResult -> Bool
/= :: CacheResult -> CacheResult -> Bool
Eq, (forall x. CacheResult -> Rep CacheResult x)
-> (forall x. Rep CacheResult x -> CacheResult)
-> Generic CacheResult
forall x. Rep CacheResult x -> CacheResult
forall x. CacheResult -> Rep CacheResult x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. CacheResult -> Rep CacheResult x
from :: forall x. CacheResult -> Rep CacheResult x
$cto :: forall x. Rep CacheResult x -> CacheResult
to :: forall x. Rep CacheResult x -> CacheResult
Generic, Int -> CacheResult -> ShowS
[CacheResult] -> ShowS
CacheResult -> String
(Int -> CacheResult -> ShowS)
-> (CacheResult -> String)
-> ([CacheResult] -> ShowS)
-> Show CacheResult
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> CacheResult -> ShowS
showsPrec :: Int -> CacheResult -> ShowS
$cshow :: CacheResult -> String
show :: CacheResult -> String
$cshowList :: [CacheResult] -> ShowS
showList :: [CacheResult] -> ShowS
Show)

instance Universe CacheResult where universe :: [CacheResult]
universe = [CacheResult]
forall a. (Generic a, GUniverse (Rep a)) => [a]
universeGeneric

{- | A processed mirror job's result. The idempotent "already present" outcome (a
registry @409@) is __not__ a distinct value: the worker treats it as a success, so it is
counted as 'Published' -- a series that could never emit is not published.
-}
data MirrorResult = Published | Failed
    deriving stock (MirrorResult -> MirrorResult -> Bool
(MirrorResult -> MirrorResult -> Bool)
-> (MirrorResult -> MirrorResult -> Bool) -> Eq MirrorResult
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: MirrorResult -> MirrorResult -> Bool
== :: MirrorResult -> MirrorResult -> Bool
$c/= :: MirrorResult -> MirrorResult -> Bool
/= :: MirrorResult -> MirrorResult -> Bool
Eq, (forall x. MirrorResult -> Rep MirrorResult x)
-> (forall x. Rep MirrorResult x -> MirrorResult)
-> Generic MirrorResult
forall x. Rep MirrorResult x -> MirrorResult
forall x. MirrorResult -> Rep MirrorResult x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. MirrorResult -> Rep MirrorResult x
from :: forall x. MirrorResult -> Rep MirrorResult x
$cto :: forall x. Rep MirrorResult x -> MirrorResult
to :: forall x. Rep MirrorResult x -> MirrorResult
Generic, Int -> MirrorResult -> ShowS
[MirrorResult] -> ShowS
MirrorResult -> String
(Int -> MirrorResult -> ShowS)
-> (MirrorResult -> String)
-> ([MirrorResult] -> ShowS)
-> Show MirrorResult
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> MirrorResult -> ShowS
showsPrec :: Int -> MirrorResult -> ShowS
$cshow :: MirrorResult -> String
show :: MirrorResult -> String
$cshowList :: [MirrorResult] -> ShowS
showList :: [MirrorResult] -> ShowS
Show)

instance Universe MirrorResult where universe :: [MirrorResult]
universe = [MirrorResult]
forall a. (Generic a, GUniverse (Rep a)) => [a]
universeGeneric

-- | A credential-refresh result.
data CredentialResult = Refreshed | RefreshFailed
    deriving stock (CredentialResult -> CredentialResult -> Bool
(CredentialResult -> CredentialResult -> Bool)
-> (CredentialResult -> CredentialResult -> Bool)
-> Eq CredentialResult
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: CredentialResult -> CredentialResult -> Bool
== :: CredentialResult -> CredentialResult -> Bool
$c/= :: CredentialResult -> CredentialResult -> Bool
/= :: CredentialResult -> CredentialResult -> Bool
Eq, (forall x. CredentialResult -> Rep CredentialResult x)
-> (forall x. Rep CredentialResult x -> CredentialResult)
-> Generic CredentialResult
forall x. Rep CredentialResult x -> CredentialResult
forall x. CredentialResult -> Rep CredentialResult x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. CredentialResult -> Rep CredentialResult x
from :: forall x. CredentialResult -> Rep CredentialResult x
$cto :: forall x. Rep CredentialResult x -> CredentialResult
to :: forall x. Rep CredentialResult x -> CredentialResult
Generic, Int -> CredentialResult -> ShowS
[CredentialResult] -> ShowS
CredentialResult -> String
(Int -> CredentialResult -> ShowS)
-> (CredentialResult -> String)
-> ([CredentialResult] -> ShowS)
-> Show CredentialResult
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> CredentialResult -> ShowS
showsPrec :: Int -> CredentialResult -> ShowS
$cshow :: CredentialResult -> String
show :: CredentialResult -> String
$cshowList :: [CredentialResult] -> ShowS
showList :: [CredentialResult] -> ShowS
Show)

instance Universe CredentialResult where universe :: [CredentialResult]
universe = [CredentialResult]
forall a. (Generic a, GUniverse (Rep a)) => [a]
universeGeneric

-- | Which circuit breaker a state gauge concerns.
data BreakerSource = EffectfulRule | CredentialMint
    deriving stock (BreakerSource -> BreakerSource -> Bool
(BreakerSource -> BreakerSource -> Bool)
-> (BreakerSource -> BreakerSource -> Bool) -> Eq BreakerSource
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: BreakerSource -> BreakerSource -> Bool
== :: BreakerSource -> BreakerSource -> Bool
$c/= :: BreakerSource -> BreakerSource -> Bool
/= :: BreakerSource -> BreakerSource -> Bool
Eq, (forall x. BreakerSource -> Rep BreakerSource x)
-> (forall x. Rep BreakerSource x -> BreakerSource)
-> Generic BreakerSource
forall x. Rep BreakerSource x -> BreakerSource
forall x. BreakerSource -> Rep BreakerSource x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. BreakerSource -> Rep BreakerSource x
from :: forall x. BreakerSource -> Rep BreakerSource x
$cto :: forall x. Rep BreakerSource x -> BreakerSource
to :: forall x. Rep BreakerSource x -> BreakerSource
Generic, Int -> BreakerSource -> ShowS
[BreakerSource] -> ShowS
BreakerSource -> String
(Int -> BreakerSource -> ShowS)
-> (BreakerSource -> String)
-> ([BreakerSource] -> ShowS)
-> Show BreakerSource
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> BreakerSource -> ShowS
showsPrec :: Int -> BreakerSource -> ShowS
$cshow :: BreakerSource -> String
show :: BreakerSource -> String
$cshowList :: [BreakerSource] -> ShowS
showList :: [BreakerSource] -> ShowS
Show)

instance Universe BreakerSource where universe :: [BreakerSource]
universe = [BreakerSource]
forall a. (Generic a, GUniverse (Rep a)) => [a]
universeGeneric

{- | The circuit-breaker state, recorded as the value of the @ecluse.rule.breaker.state@
gauge (labelled by 'BreakerSource'). It is a bounded measurement, not a label.
-}
data BreakerState = Closed | HalfOpen | Open
    deriving stock (BreakerState -> BreakerState -> Bool
(BreakerState -> BreakerState -> Bool)
-> (BreakerState -> BreakerState -> Bool) -> Eq BreakerState
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: BreakerState -> BreakerState -> Bool
== :: BreakerState -> BreakerState -> Bool
$c/= :: BreakerState -> BreakerState -> Bool
/= :: BreakerState -> BreakerState -> Bool
Eq, (forall x. BreakerState -> Rep BreakerState x)
-> (forall x. Rep BreakerState x -> BreakerState)
-> Generic BreakerState
forall x. Rep BreakerState x -> BreakerState
forall x. BreakerState -> Rep BreakerState x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. BreakerState -> Rep BreakerState x
from :: forall x. BreakerState -> Rep BreakerState x
$cto :: forall x. Rep BreakerState x -> BreakerState
to :: forall x. Rep BreakerState x -> BreakerState
Generic, Int -> BreakerState -> ShowS
[BreakerState] -> ShowS
BreakerState -> String
(Int -> BreakerState -> ShowS)
-> (BreakerState -> String)
-> ([BreakerState] -> ShowS)
-> Show BreakerState
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> BreakerState -> ShowS
showsPrec :: Int -> BreakerState -> ShowS
$cshow :: BreakerState -> String
show :: BreakerState -> String
$cshowList :: [BreakerState] -> ShowS
showList :: [BreakerState] -> ShowS
Show)

instance Universe BreakerState where universe :: [BreakerState]
universe = [BreakerState]
forall a. (Generic a, GUniverse (Rep a)) => [a]
universeGeneric

{- | The gauge code for a breaker state: @0@ closed, @1@ half-open, @2@ open -- a small
ordinal so a dashboard can alarm on "not closed" without a high-cardinality label.
-}
breakerStateCode :: BreakerState -> Int64
breakerStateCode :: BreakerState -> Int64
breakerStateCode = \case
    BreakerState
Closed -> Int64
0
    BreakerState
HalfOpen -> Int64
1
    BreakerState
Open -> Int64
2

{- | A single metric label: a bounded key paired with its bounded value. There is no
constructor for a package, version, scope, or message, so a high-cardinality identifier
cannot be turned into a label. 'LRule' carries a rule's configured name -- the one
operator-bounded label (a deployment defines a small, fixed rule set).
-}
data Label
    = LDecision Decision
    | LReasonClass ReasonClass
    | LRule Text
    | LEcosystem Ecosystem
    | LMount Ecosystem
    | LUpstream Upstream
    | LStatusClass StatusClass
    | LCacheResult CacheResult
    | LMirrorResult MirrorResult
    | LCredentialResult CredentialResult
    | LProvider Provider
    | LCause Cause
    | LBreakerSource BreakerSource
    | LTier Tier
    deriving stock (Label -> Label -> Bool
(Label -> Label -> Bool) -> (Label -> Label -> Bool) -> Eq Label
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Label -> Label -> Bool
== :: Label -> Label -> Bool
$c/= :: Label -> Label -> Bool
/= :: Label -> Label -> Bool
Eq, Int -> Label -> ShowS
[Label] -> ShowS
Label -> String
(Int -> Label -> ShowS)
-> (Label -> String) -> ([Label] -> ShowS) -> Show Label
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Label -> ShowS
showsPrec :: Int -> Label -> ShowS
$cshow :: Label -> String
show :: Label -> String
$cshowList :: [Label] -> ShowS
showList :: [Label] -> ShowS
Show)

-- | The 'LabelKey' a 'Label' is filed under.
labelKey :: Label -> LabelKey
labelKey :: Label -> LabelKey
labelKey = \case
    LDecision{} -> LabelKey
KeyDecision
    LReasonClass{} -> LabelKey
KeyReasonClass
    LRule{} -> LabelKey
KeyRule
    LEcosystem{} -> LabelKey
KeyEcosystem
    LMount{} -> LabelKey
KeyMount
    LUpstream{} -> LabelKey
KeyUpstream
    LStatusClass{} -> LabelKey
KeyStatusClass
    LCacheResult{} -> LabelKey
KeyResult
    LMirrorResult{} -> LabelKey
KeyResult
    LCredentialResult{} -> LabelKey
KeyResult
    LProvider{} -> LabelKey
KeyProvider
    LCause{} -> LabelKey
KeyCause
    LBreakerSource{} -> LabelKey
KeyBreakerSource
    LTier{} -> LabelKey
KeyTier

-- | Project a 'Label' to its @(key, value)@ wire pair.
renderLabel :: Label -> (Text, Text)
renderLabel :: Label -> (Text, Text)
renderLabel Label
label = (LabelKey -> Text
labelKeyName (Label -> LabelKey
labelKey Label
label), Label -> Text
labelValue Label
label)

labelValue :: Label -> Text
labelValue :: Label -> Text
labelValue = \case
    LDecision Decision
d -> case Decision
d of
        Decision
Admit -> Text
"admit"
        Decision
Deny -> Text
"deny"
        Decision
Unavailable -> Text
"unavailable"
    LReasonClass ReasonClass
r -> case ReasonClass
r of
        ReasonClass
ReasonPolicy -> Text
"policy"
        ReasonClass
ReasonMissingIntegrity -> Text
"missing_integrity"
        ReasonClass
ReasonUnavailable -> Text
"unavailable"
        ReasonClass
ReasonLimit -> Text
"limit"
    LRule Text
name -> Text
name
    LEcosystem Ecosystem
eco -> Ecosystem -> Text
ecosystemName Ecosystem
eco
    LMount Ecosystem
eco -> Ecosystem -> Text
ecosystemName Ecosystem
eco
    LUpstream Upstream
u -> case Upstream
u of
        Upstream
Private -> Text
"private"
        Upstream
Public -> Text
"public"
    LStatusClass StatusClass
s -> case StatusClass
s of
        StatusClass
Status2xx -> Text
"2xx"
        StatusClass
Status3xx -> Text
"3xx"
        StatusClass
Status4xx -> Text
"4xx"
        StatusClass
Status5xx -> Text
"5xx"
        StatusClass
StatusOther -> Text
"other"
    LCacheResult CacheResult
c -> case CacheResult
c of
        CacheResult
Hit -> Text
"hit"
        CacheResult
Miss -> Text
"miss"
    LMirrorResult MirrorResult
m -> case MirrorResult
m of
        MirrorResult
Published -> Text
"published"
        MirrorResult
Failed -> Text
"failed"
    LCredentialResult CredentialResult
c -> case CredentialResult
c of
        CredentialResult
Refreshed -> Text
"refreshed"
        CredentialResult
RefreshFailed -> Text
"failed"
    LProvider Provider
p -> case Provider
p of
        Provider
CodeArtifact -> Text
"codeartifact"
        Provider
Static -> Text
"static"
        Provider
Adc -> Text
"adc"
    LCause Cause
c -> case Cause
c of
        Cause
Timeout -> Text
"timeout"
        Cause
Connection -> Text
"connection"
        Cause
Decode -> Text
"decode"
        Cause
UpstreamStatus -> Text
"upstream_status"
        Cause
OtherCause -> Text
"other"
    LBreakerSource BreakerSource
b -> case BreakerSource
b of
        BreakerSource
EffectfulRule -> Text
"effectful_rule"
        BreakerSource
CredentialMint -> Text
"credential_mint"
    LTier Tier
t -> case Tier
t of
        Tier
Structural -> Text
"structural"
        Tier
Effectful -> Text
"effectful"

{- | Classify an HTTP status code into its bounded 'StatusClass', so a status never
becomes a per-code label.
-}
statusClassOf :: Int -> StatusClass
statusClassOf :: Int -> StatusClass
statusClassOf Int
code
    | Int
code Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
200 Bool -> Bool -> Bool
&& Int
code Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
300 = StatusClass
Status2xx
    | Int
code Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
300 Bool -> Bool -> Bool
&& Int
code Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
400 = StatusClass
Status3xx
    | Int
code Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
400 Bool -> Bool -> Bool
&& Int
code Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
500 = StatusClass
Status4xx
    | Int
code Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
500 Bool -> Bool -> Bool
&& Int
code Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
600 = StatusClass
Status5xx
    | Bool
otherwise = StatusClass
StatusOther

{- | Materialise a label list into the OpenTelemetry 'Attributes' an instrument is
recorded with. Every value is bounded, so the attribute set an instrument ever sees is
drawn from a small fixed product of the label domains -- never the unbounded space of
package identifiers.
-}
metricAttributes :: [Label] -> Attributes
metricAttributes :: [Label] -> Attributes
metricAttributes [Label]
labels =
    AttributeLimits -> Attributes -> AttrsBuilder -> Attributes
addAttributesFromBuilder
        AttributeLimits
defaultAttributeLimits
        Attributes
emptyAttributes
        ((Label -> AttrsBuilder) -> [Label] -> AttrsBuilder
forall m a. Monoid m => (a -> m) -> [a] -> m
forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap (\Label
label -> let (Text
key, Text
value) = Label -> (Text, Text)
renderLabel Label
label in Text -> Text -> AttrsBuilder
forall a. ToAttribute a => Text -> a -> AttrsBuilder
attr Text
key Text
value) [Label]
labels)