Skip to content

Metrics Reference

sf2loki emits its own operational metrics via OTLP — there is no Prometheus /metrics scrape endpoint, the connector is OTLP-native and pushes on an interval. This page is the canonical reference for every instrument, generated by reading src/sf2loki/obs/metrics.py.

All instruments carry an org label when multi-org ingestion is enabled (for_org() stamps it on per-org components — token provider, Salesforce clients, sources, the limits poller); single-org deployments omit it. Names below are exactly as created in code — unsuffixed. See Metric-name suffixes before wiring dashboards or alerts against them.

Enabling metrics

Set service.telemetry.enabled: true and service.telemetry.endpoint:

service:
  telemetry:
    enabled: true
    endpoint: https://otlp-gateway-<zone>.grafana.net/otlp/v1/metrics
    # endpoint: http://alloy:4318/v1/metrics   # local Alloy instead of Grafana Cloud
  • Grafana Cloud — basic auth defaults to the Loki sink's tenant_id / auth_token (one stack credential covers both Loki and OTLP).
  • Local/in-cluster Alloy — set service.telemetry.auth: none for an unauthenticated collector.
  • Enable Salesforce org-limit gauges (API usage, storage, streaming events) with salesforce.limits.enabled: true.

See Configuration for the full service.telemetry field reference.

Metric-name suffixes

Keep add_metric_suffixes on, or dashboards/alerts go blank

Instruments are created unsuffixed in code (e.g. sf2loki_events_ingested), but the OpenTelemetry→Prometheus bridge appends _total (counters), _bucket/_count/_sum (histograms) on export — e.g. sf2loki_events_ingested_total, sf2loki_ingest_lag_seconds_bucket. Grafana Cloud's OTLP endpoint adds these suffixes by default. If you route metrics through your own OpenTelemetry Collector or Grafana Alloy instead, keep add_metric_suffixes (a.k.a. AddMetricSuffixes) enabled on the Prometheus exporter — with it off, the connector-health dashboard and every connector metric alert query the suffixed names and return nothing.

Gauges are queried by their bare name (no suffix) in both cases.

Instruments

Metric nameTypeLabelsMeaning
sf2loki_events_ingestedCounter(none)Total events ingested from Salesforce sources
sf2loki_decode_errorsCounter(none)Total Avro/payload decode errors
sf2loki_loki_pushCounter(none)Total Loki push attempts
sf2loki_loki_entries_droppedCounter(none)Loki entries dropped as undeliverable (permanent errors), per reason
sf2loki_loki_push_duration_secondsHistogram(none)Duration of Loki push requests in seconds
sf2loki_loki_bytes_pushedCounter(none)Total bytes pushed to Loki
sf2loki_last_push_success_timestamp_secondsGauge(none)Unix ts of the last successful Loki push
sf2loki_ingest_lag_secondsHistogramper event typenow - event EventDate (the ingest-lag SLI). Bucket boundaries extend to 24h (1, 5, 15, 60, 300, 900, 1800, 3600, 7200, 14400, 28800, 86400) because EventLogFile lag is legitimately 3-6h
sf2loki_last_replay_commit_timestamp_secondsGaugeper topicUnix ts of the last committed replay_id
sf2loki_pubsub_pending_creditsGaugeper topicPending Pub/Sub flow-control credits
sf2loki_pubsub_reconnectsCounterper topicTotal Pub/Sub stream reconnects
sf2loki_pubsub_replay_fallbacksCounterper topicSubscriptions restarted with a fallback replay preset after an invalid/expired replay id
sf2loki_pubsub_stream_stallsCounterper topicPub/Sub streams force-reconnected by the keepalive watchdog
sf2loki_salesforce_api_throttledCounterper apiSalesforce REST calls rejected with REQUEST_LIMIT_EXCEEDED
sf2loki_pubsub_stream_upGaugeper topic1 while a topic's subscribe stream is connected and healthy, 0 while erroring/reconnecting
sf2loki_watermark_timestamp_secondsGaugeper source/objectUnix ts of the current polling watermark
sf2loki_watermark_stallsCounterper source/objectPoll cycles that made no progress because a full page shared one timestamp boundary (a compound-cursor stall would silently drop newer data)
sf2loki_pubsub_decode_stallsCounterper topicTopics stuck making zero progress — consecutive batches at 100% decode failure, or repeated schema-fetch failures
sf2loki_checkpoint_load_errorsCounterper sourceStored checkpoint values that failed to load/decode and fell back to a replay preset / lookback
sf2loki_auth_refreshesCounter(none)Total Salesforce OAuth token refreshes
sf2loki_auth_errorsCounter(none)Total Salesforce auth errors
sf2loki_schema_cache_sizeGauge(none)Avro schemas in the codec cache
sf2loki_queue_depthGauge(none)Depth of the internal event queue
sf2loki_eventlogfile_files_processedCounterper event typeEventLogFile records downloaded and parsed
sf2loki_eventlogfile_rows_ingestedCounterper event typeCSV rows ingested from EventLogFiles
sf2loki_eventlogfile_download_bytesCounter(none)Bytes downloaded from EventLogFile LogFile endpoints
sf2loki_eventlogfile_download_errorsCounterper reasonEventLogFile listing/download errors
sf2loki_soql_poll_errorsCounterper source and object/event typeFailed SOQL poll cycles
sf2loki_apexlog_logs_ingestedCounter(none)ApexLog debug logs ingested
sf2loki_apexlog_download_bytesCounter(none)Bytes downloaded from ApexLog Body endpoints
sf2loki_apexlog_bodies_skippedCounterper reasonApexLog bodies not shipped (over max_body_bytes or download error)
sf2loki_apexlog_download_errorsCounterper reasonApexLog body download errors
sf2loki_timestamp_fallbacksCounterper sourceEntries whose event timestamp was missing/unparseable and a fallback was used
sf2loki_lines_truncatedCounterper sourceLog lines truncated to max_line_bytes
sf2loki_entries_sampled_outCounterper source and event typeRows/events dropped by deterministic per-type sampling
sf2loki_rows_filteredCounterper source and ruleRows dropped by transform drop_row rules
sf2loki_egress_budget_used_bytesGauge(none)Pre-compression bytes counted against the daily egress budget (current UTC day)
sf2loki_egress_pausedGauge(none)1 while pushes are paused by the daily byte budget, else 0
sf2loki_eventlogfile_cycle_secondsGauge(none)Wall-clock duration of the last EventLogFile poll cycle
sf2loki_leaderGauge(none)1 while this instance holds leadership (or runs standalone), else 0
sf2loki_salesforce_limit_maxGaugeper limit_nameSalesforce org limit maximum (requires salesforce.limits.enabled: true)
sf2loki_salesforce_limit_remainingGaugeper limit_nameSalesforce org limit remaining (requires salesforce.limits.enabled: true)
sf2loki_salesforce_limits_poll_errorsCounter(none)Total Salesforce /limits poll errors
sf2loki_build_infoGaugeversionBuild metadata; value is always 1

All labels above are in addition to the org label added under multi-org ingestion (see above); "(none)" means no labels other than a possible org.

Where these are used

  • Dashboards — the bundled sf2loki-connector-health dashboard graphs these metrics (suffixed) from a Prometheus datasource.
  • Alerts — the Grafana-managed alert pack thresholds several of these (ingest lag, Loki push failure rate, org-limit headroom).
  • State & checkpointssf2loki_watermark_timestamp_seconds, sf2loki_last_replay_commit_timestamp_seconds, and sf2loki_checkpoint_load_errors are the checkpoint-health signals.
  • High availabilitysf2loki_leader reflects lease ownership under the active-passive coordinator.