Set Up Metrics
Metrics allow you to send, view and query counters, gauges, and distributions from your Sentry-configured apps to track application health and drill down into related traces, logs, and errors.
With Sentry Metrics, you can send counters, gauges, and distributions from your applications to Sentry. Once in Sentry, these metrics can be viewed alongside relevant errors, traces, and logs, and searched using their individual attributes.
This feature is currently in open beta. Please reach out on GitHub if you have feedback or questions. Features in beta are still in-progress and may have bugs. We recognize the irony.
Metrics are supported in Sentry Cocoa SDK version 9.2.0 and above.
Once the SDK is initialized, you can send metrics using the SentrySDK.metrics APIs. Metrics are enabled by default.
The metrics namespace exposes three methods that you can use to capture different types of metric information: count, gauge and distribution.
Objective-C support for metrics is not currently available. If you need Objective-C support, please open an issue to show demand for this feature.
Counters track discrete occurrence counts. Use this to increment or set a count associated with a metric key, such as the number of events, requests, or errors.
Key characteristics:
- Values are typically non-negative integers
- Use descriptive, lowercase, dot-delimited names (e.g.,
"network.request.count")
import Sentry
// Simple counter
SentrySDK.metrics.count(key: "button_click", value: 1)
// Counter with unit and attributes
SentrySDK.metrics.count(
key: "network.request.count",
value: 1,
unit: .generic("request"),
attributes: ["endpoint": "/api/users", "method": "POST"]
)
Gauges track values that can go up and down over time, representing a current state rather than an incrementing counter. Use this for metrics like current memory usage, queue depth, or active connections.
Key characteristics:
- Values can increase or decrease
- Represents the state at the time of recording
- Supports aggregates like min, max, avg, sum, and count
- Cannot be used to calculate percentiles (use distributions for that)
import Sentry
// Simple gauge
SentrySDK.metrics.gauge(key: "queue_depth", value: 42.0)
// Gauge with unit
SentrySDK.metrics.gauge(
key: "memory.usage",
value: 1024.0,
unit: .megabyte
)
Distributions track the distribution of a value over time, allowing you to analyze statistical properties like mean, median, and percentiles. Use this for measurable quantities like response times or request durations.
Key characteristics:
- Enables percentile calculations (p50, p90, p99, etc.)
- Best for analyzing statistical properties of measurements
- Use for values where you need to understand distribution, not just aggregates
import Sentry
// Simple distribution
SentrySDK.metrics.distribution(key: "response_time", value: 187.5)
// Distribution with unit and attributes
SentrySDK.metrics.distribution(
key: "http.request.duration",
value: 187.5,
unit: .millisecond,
attributes: ["endpoint": "/api/data", "cached": false]
)
You can also pass additional attributes to any of the metric methods via the attributes parameter. Attributes allow you to filter and group metrics.
The SDK uses the SentryAttributeValue protocol to provide compile-time type safety for attribute values. This means you can pass native Swift types directly without wrapping them, and the compiler will ensure only valid types are accepted.
Supported attribute types:
- Scalar types:
String,Bool,Int,Double,Float - Array types:
[String],[Bool],[Int],[Double],[Float]
The protocol automatically handles type conversion and validation, so you can use Swift's native types directly in your code. Invalid types will be caught at compile time, preventing runtime errors.
import Sentry
SentrySDK.metrics.count(
key: "button_click",
value: 1,
unit: nil,
attributes: [
"browser": "Firefox", // String - passed directly
"app_version": "1.0.0", // String - passed directly
"build_number": 123, // Int - passed directly
"is_premium": true, // Bool - passed directly
"success_rate": 0.95, // Double - passed directly
"tags": ["production", "v2"] // [String] - passed directly
]
)
The SentryAttributeValue protocol ensures that all these types are automatically converted to the correct internal representation, providing both type safety and a clean, idiomatic Swift API.
All metric types (count, gauge, and distribution) support the optional unit parameter. Units help Sentry display metric values in a human-readable format.
The SDK provides the SentryUnit enum with type-safe unit values:
import Sentry
// Use enum cases for type safety (recommended)
SentrySDK.metrics.distribution(
key: "response_time",
value: 187.5,
unit: .millisecond
)
SentrySDK.metrics.gauge(
key: "memory_usage",
value: 1024.0,
unit: .byte
)
SentrySDK.metrics.distribution(
key: "cache_latency",
value: 42.3,
unit: .microsecond
)
Available unit categories:
- Duration:
.nanosecond,.microsecond,.millisecond,.second,.minute,.hour,.day,.week - Information:
.bit,.byte,.kilobyte,.kibibyte,.megabyte,.mebibyte,.gigabyte,.gibibyte,.terabyte,.tebibyte,.petabyte,.pebibyte,.exabyte,.exbibyte - Fraction:
.ratio,.percent - Custom:
.generic("custom_unit")for any other unit
You can also use string literals (e.g., unit: "millisecond"), which are automatically converted to the corresponding enum case. However, using enum cases is recommended for compile-time safety.
The Sentry Cocoa SDK provides several options to configure how metrics are captured and sent to Sentry.
Metrics are enabled by default, but are not collected automatically. You must manually call the SentrySDK.metrics API to record metrics. If you need to disable metrics entirely, set options.experimental.enableMetrics to false when initializing the SDK:
import Sentry
SentrySDK.start { options in
options.dsn = "___PUBLIC_DSN___"
options.experimental.enableMetrics = false // Metrics are enabled by default
}
Use the beforeSendMetric callback to filter or modify metrics before they're sent to Sentry. This is useful for:
- Removing sensitive data from metric attributes
- Dropping metrics you don't want to send
- Adding or modifying attributes
- Changing metric names or units
The callback receives a SentryMetric struct and must return either a modified metric or nil to drop it.
Available SentryMetric properties:
name: The metric name (e.g., "api.response_time")value: The metric value (SentryMetricValue- counter, distribution, or gauge)unit: The unit of measurement (SentryUnit?)attributes: Dictionary of attributes ([String: SentryAttributeContent])timestamp: When the metric was recordedtraceId: Associated trace ID for distributed tracing correlation
When modifying attributes, you can assign values directly using literals thanks to Swift's ExpressibleBy...Literal protocols. The SDK supports String, Bool, Int, Double, and arrays of these types.
import Sentry
SentrySDK.start { options in
options.dsn = "___PUBLIC_DSN___"
// Metrics are enabled by default, no need to set enableMetrics = true
options.experimental.beforeSendMetric = { metric in
// Create a mutable copy (SentryMetric is a struct)
var metric = metric
// Drop metrics based on attributes
if case .boolean(let dropMe) = metric.attributes["dropMe"], dropMe {
return nil
}
// Drop metrics by name
if metric.name.hasPrefix("internal.") {
return nil
}
// Modify or add attributes using literals (recommended)
metric.attributes["processed"] = true // Boolean literal
metric.attributes["environment"] = "production" // String literal
metric.attributes["retry_count"] = 3 // Integer literal
metric.attributes["latency"] = 42.5 // Double literal
// You can also use enum cases for explicitness
metric.attributes["explicit"] = .boolean(true)
metric.attributes["tags"] = .stringArray(["tag1", "tag2"])
// Change the metric name
if metric.name == "legacy_metric" {
metric.name = "new_metric_name"
}
return metric
}
}
By default, metrics are buffered and flushed depending on buffer size and time. If you need to manually flush metrics before the automatic interval, you can use the flush method. Note that this is a blocking call that will wait until all pending data is sent or the timeout is reached:
import Sentry
SentrySDK.flush(timeout: 5.0)
This will flush all pending metrics and events to Sentry.
By default the SDK will attach the following attributes to a metric:
device.brand: Always "Apple" for Apple devices.device.model: The device model (e.g., "iPhone14,2").device.family: The device family (e.g., "iPhone").os.name: The operating system name (e.g., "iOS").os.version: The operating system version.
user.id: The user ID from the current scope. Falls back to the installation ID if no user is set.user.name: The username from the current scope.user.email: The email address from the current scope.
sentry.sdk.name: The name of the SDK that sent the metric (e.g., "sentry.cocoa").sentry.sdk.version: The version of the SDK that sent the metric.sentry.environment: The environment set in the SDK.sentry.release: The release set in the SDK, if defined.
If there is an active span when the metric is recorded, the following attribute is added:
span_id: The span ID of the active span.
The trace_id is set as a top-level field on the metric (not as an attribute) to enable distributed tracing correlation. When a span is active, the SDK uses that span's trace ID; otherwise, it falls back to the propagation context's trace ID.
If Session Replay is enabled and active (iOS and tvOS only):
sentry.replay_id: The current replay session ID.
Our documentation is open source and available on GitHub. Your contributions are welcome, whether fixing a typo (drat!) or suggesting an update ("yeah, this would be better").