Skip to content

Application Metrics Reference

Every Granit module exposes business-level metrics via the .NET System.Diagnostics.Metrics API. These metrics are automatically exported to Mimir (or any OpenTelemetry-compatible backend) by AddGranitObservability() — no manual wiring needed.

All Granit metrics follow strict naming and tagging conventions:

RuleConvention
File locationsrc/Granit.{Module}/Diagnostics/{Module}Metrics.cs
Classsealed class {Module}Metrics with IMeterFactory constructor injection
Meter nameGranit.{Module} (PascalCase, one per module)
Metric namegranit.{module}.{entity}.{action} (all lowercase, dot-separated)
Tagssnake_case, always include tenant_id (coalesced to "global" when null)
Tag passingTagList (zero-allocation struct) — never KeyValuePair[]
DI registrationservices.TryAddSingleton<{Module}Metrics>() in AddGranit*()
Duration unitseconds ("s"), measured via Stopwatch.GetElapsedTime()
.NET typeOpenTelemetry kindUse case
Counter<long>Monotonic sumEvents counted (requests, deliveries, errors)
Histogram<double>DistributionLatency, duration
UpDownCounter<long>Non-monotonic sumIn-flight operations (active leases)
namespace Granit.MyModule.Diagnostics;
public sealed class MyModuleMetrics(IMeterFactory meterFactory)
{
private readonly Meter _meter = meterFactory.Create("Granit.MyModule");
private readonly Counter<long> _operationsCompleted;
private readonly Histogram<double> _operationDuration;
// Initialize instruments in a method or constructor body
// ...
public void RecordOperationCompleted(Guid? tenantId, string status)
{
var tags = new TagList
{
{ "tenant_id", tenantId?.ToString() ?? "global" },
{ "status", status },
};
_operationsCompleted.Add(1, tags);
}
public void RecordOperationDuration(Guid? tenantId, double seconds)
{
var tags = new TagList
{
{ "tenant_id", tenantId?.ToString() ?? "global" },
};
_operationDuration.Record(seconds, tags);
}
}

Meter: Granit.AI

MetricTypeTagsDescription
granit.ai.requests.completedCountertenant_id, model, provider, statusLLM requests completed
granit.ai.tokens.inputCountertenant_id, model, providerInput tokens consumed
granit.ai.tokens.outputCountertenant_id, model, providerOutput tokens generated
granit.ai.request.durationHistogram (s)tenant_id, model, providerLLM request duration

Meter: Granit.Auditing

MetricTypeTagsDescription
granit.auditing.entries.persistedCountertenant_id, entity_typeAudit entries written
granit.auditing.entries.purgedCountertenant_idAudit entries purged (retention)
granit.auditing.capture.errorsCountertenant_id, entity_typeCapture failures

Meter: Granit.BackgroundJobs

MetricTypeTagsDescription
granit.background_jobs.execution.completedCountertenant_id, job_name, statusJob executions completed
granit.background_jobs.execution.durationHistogram (s)tenant_id, job_name, statusJob execution duration

Meter: Granit.BlobStorage

MetricTypeTagsDescription
granit.blob_storage.uploads.initiatedCountertenant_id, providerUpload operations started
granit.blob_storage.validations.completedCountertenant_id, statusBlob validations completed
granit.blob_storage.validations.failedCountertenant_id, reasonBlob validations failed
granit.blob_storage.blobs.deletedCountertenant_idBlobs deleted
granit.blob_storage.orphans.cleanedCountertenant_idOrphan blobs cleaned up
granit.blob_storage.confirm.durationHistogram (s)tenant_id, providerBlob confirmation duration

Meter: Granit.DataExchange

MetricTypeTagsDescription
granit.data_exchange.import.jobs.completedCountertenant_id, statusImport jobs completed
granit.data_exchange.import.rows.processedCountertenant_idRows processed during import
granit.data_exchange.import.rows.errorsCountertenant_idRows that failed during import
granit.data_exchange.import.durationHistogram (s)tenant_idImport job duration
granit.data_exchange.export.jobs.completedCountertenant_id, statusExport jobs completed
granit.data_exchange.export.rows.exportedCountertenant_idRows exported
granit.data_exchange.export.durationHistogram (s)tenant_idExport job duration

Meter: Granit.Events

MetricTypeTagsDescription
granit.events.event.publishedCountertenant_id, bus_type, event_typeEvents published (local or distributed)
granit.events.handler.executedCountertenant_id, event_type, statusEvent handler executions

Meter: Granit.Identity

MetricTypeTagsDescription
granit.identity.operations.completedCountertenant_id, operation, provider, statusIdentity operations completed
granit.identity.operations.errorsCountertenant_id, operation, providerIdentity operation errors
granit.identity.operation.durationHistogram (s)tenant_id, operation, providerIdentity operation duration

Meter: Granit.Notifications

MetricTypeTagsDescription
granit.notifications.fanout.triggeredCountertenant_id, notification_typeNotification fanouts triggered
granit.notifications.deliveries.succeededCountertenant_id, channelDeliveries succeeded
granit.notifications.deliveries.failedCountertenant_id, channelDeliveries failed
granit.notifications.delivery.durationHistogram (s)tenant_id, channel, statusDelivery duration

Meter: Granit.Privacy

MetricTypeTagsDescription
granit.privacy.export.requestsCountertenant_idGDPR export requests initiated
granit.privacy.export.fragments.receivedCountertenant_id, providerData fragments received during export
granit.privacy.deletion.requestsCountertenant_idGDPR deletion requests initiated
granit.privacy.export.durationHistogram (s)tenant_id, statusExport saga duration

Meter: Granit.RateLimiting

MetricTypeTagsDescription
granit.rate_limiting.requests.allowedCountertenant_id, policyRequests allowed through rate limiter
granit.rate_limiting.requests.rejectedCountertenant_id, policyRequests rejected by rate limiter

Meter: Granit.Http.Bulkhead

MetricTypeTagsDescription
granit.http.bulkhead.leases.activeUpDownCountertenant_idCurrently active bulkhead leases
granit.http.bulkhead.requests.rejectedCountertenant_idRequests rejected by bulkhead

Meter: Granit.Vault

MetricTypeTagsDescription
granit.vault.operations.completedCountertenant_id, operation, provider, statusVault operations completed
granit.vault.operations.errorsCountertenant_id, operation, providerVault operation errors
granit.vault.operation.durationHistogram (s)tenant_id, operation, providerVault operation duration
granit.vault.rotations.detectedCounterproviderKey rotations detected

Meter: Granit.Webhooks

MetricTypeTagsDescription
granit.webhooks.fanout.triggeredCountertenant_id, event_typeWebhook fanouts triggered
granit.webhooks.deliveries.succeededCountertenant_id, event_typeWebhook deliveries succeeded
granit.webhooks.deliveries.failedCountertenant_id, event_type, statusWebhook deliveries failed
granit.webhooks.subscriptions.suspendedCountertenant_idSubscriptions auto-suspended
granit.webhooks.delivery.durationHistogram (s)tenant_id, event_type, statusWebhook delivery duration

Meter: Granit.Workflow

MetricTypeTagsDescription
granit.workflow.transitions.completedCountertenant_id, outcome, from_state, to_stateWorkflow transitions completed
granit.workflow.transition.durationHistogram (s)tenant_id, outcomeTransition evaluation duration
# Request throughput by module (last 5 min)
sum by (job) (
rate(granit_ai_requests_completed_total[5m])
or rate(granit_notifications_fanout_triggered_total[5m])
or rate(granit_webhooks_fanout_triggered_total[5m])
or rate(granit_eventbus_events_published_total[5m])
)
# Webhook delivery error rate per tenant
sum by (tenant_id) (rate(granit_webhooks_deliveries_failed_total[5m]))
/
(
sum by (tenant_id) (rate(granit_webhooks_deliveries_succeeded_total[5m]))
+ sum by (tenant_id) (rate(granit_webhooks_deliveries_failed_total[5m]))
)
# P95 vault operation duration
histogram_quantile(0.95, sum by (le, provider) (
rate(granit_vault_operation_duration_seconds_bucket[5m])
))
# Token usage per model (last 1 hour)
sum by (model) (
increase(granit_ai_tokens_input_total[1h])
+ increase(granit_ai_tokens_output_total[1h])
)
# Export requests per tenant (last 24h)
sum by (tenant_id) (increase(granit_privacy_export_requests_total[24h]))
# Average export duration
histogram_quantile(0.5, sum by (le) (
rate(granit_privacy_export_duration_seconds_bucket[24h])
))
AlertPromQL conditionSeverity
High webhook failure raterate(granit_webhooks_deliveries_failed_total[5m]) > 0.1Warning
Vault operation errorsincrease(granit_vault_operations_errors_total[5m]) > 0Critical
Slow AI responseshistogram_quantile(0.95, rate(granit_ai_request_duration_seconds_bucket[5m])) > 30Warning
Background job failuresrate(granit_backgroundjobs_executions_completed_total{status="error"}[5m]) > 0Warning
Notification delivery failuresrate(granit_notifications_deliveries_failed_total[5m]) > 0.05Warning
Webhook subscription suspendedincrease(granit_webhooks_subscriptions_suspended_total[1h]) > 0Warning