Documentation
¶
Overview ¶
Package fields defines standard log field names used across all GitLab services. Using these constants ensures consistent field naming in structured logs, making it possible to query and correlate events across services in centralised logging infrastructure.
All field names follow the existing GitLab logging conventions and must be replicated across LabKit language implementations (Go, Ruby) to maintain cross-service consistency.
Usage ¶
import (
"log/slog"
"gitlab.com/gitlab-org/labkit/v2/fields"
)
logger.Info("request completed",
slog.String(fields.CorrelationID, corrID),
slog.Int(fields.HTTPStatusCode, 200),
slog.Float64(fields.DurationS, elapsed.Seconds()),
)
Example ¶
Example shows how to use the canonical field name constants with slog. Using shared constants across services keeps field names consistent in Elasticsearch and Kibana dashboards.
package main
import (
"context"
"log/slog"
"gitlab.com/gitlab-org/labkit/v2/fields"
)
func main() {
logger := slog.Default()
logger.LogAttrs(context.Background(), slog.LevelInfo, "request handled",
slog.String(fields.CorrelationID, "req-abc-123"),
slog.String(fields.HTTPMethod, "GET"),
slog.String(fields.HTTPURL, "https://example.com/api/projects"),
slog.Int(fields.HTTPStatusCode, 200),
slog.Float64(fields.DurationS, 0.032),
slog.String(fields.RemoteIP, "203.0.113.42"),
)
}
Output:
Index ¶
Examples ¶
Constants ¶
const ( // CorrelationID Unique identifier for correlating requests across services. // Should be present in all log line emissions. CorrelationID = "correlation_id" // GitLabUserID GitLab user numeric ID. GitLabUserID = "gl_user_id" // GitLabUserName GitLab username. GitLabUserName = "gl_user_name" // DuoWorkflowDefinition Duo Workflow definition identifier (e.g. // "analytics_agent/v1"). Identifies which Duo Workflow agent originated a // request, enabling per-agent filtering in Kibana and Grafana. DuoWorkflowDefinition = "duo_workflow_definition" // DuoWorkflowID Unique identifier for a Duo Workflow instance. Identifies a // specific workflow run, enabling per-workflow tracing in logs. DuoWorkflowID = "duo_workflow_id" // ErrorType Error type or classification (e.g. "NoMethodError", // "ValidationError"). ErrorType = "error_type" // ErrorMessage Detailed error message (e.g. "undefined method 'boom!' for // nil"). ErrorMessage = "error_message" // HTTPStatusCode HTTP response status code. HTTPStatusCode = "status" // HTTPMethod HTTP method (e.g. "GET", "POST"). HTTPMethod = "method" // HTTPURL URL of an HTTP request containing only scheme, host, and path. Query // strings and fragments must be omitted to avoid logging sensitive // information. HTTPURL = "url" // DurationS Duration of any operation in seconds. Not limited to HTTP // requests; can be used for database queries, background jobs, external API // calls. Uses float64 for sub-second precision (e.g. 0.032 for 32ms). DurationS = "duration_s" // RemoteIP Remote IP address of a request. RemoteIP = "remote_ip" // TCPAddress TCP address a service is listening on, in "host:port" format // (e.g. "0.0.0.0:8080"). TCPAddress = "tcp_address" // HTTPURI Request URI including path and query string with sensitive // parameters masked (e.g. "?password=FILTERED"). HTTPURI = "uri" // HTTPHost HTTP Host header of a request (e.g. "api.gitlab.com"). HTTPHost = "host" // HTTPProto HTTP protocol version (e.g. "HTTP/1.1", "HTTP/2.0"). HTTPProto = "proto" // RemoteAddr Raw remote socket address in "host:port" format (e.g. // "10.0.0.1:54321"). Use remote_ip when only the IP is needed. RemoteAddr = "remote_addr" // HTTPReferrer HTTP Referer header with sensitive query parameters masked. HTTPReferrer = "referrer" // HTTPUserAgent HTTP User-Agent header. HTTPUserAgent = "user_agent" // WrittenBytes Number of bytes written to the HTTP response body. WrittenBytes = "written_bytes" // ContentType Content-Type of an HTTP response (e.g. "application/json"). ContentType = "content_type" // TTFBS Time to first byte of an HTTP response in seconds. Measures duration // from request receipt to first response byte written. TTFBS = "ttfb_s" // GitLabProjectID GitLab project numeric ID. GitLabProjectID = "gl_project_id" // GitLabPipelineID GitLab pipeline numeric ID. GitLabPipelineID = "gl_pipeline_id" // GitLabNamespaceID GitLab namespace numeric ID. GitLabNamespaceID = "gl_namespace_id" // GitLabRootNamespaceID GitLab root (top-level) namespace numeric ID. GitLabRootNamespaceID = "gl_root_namespace_id" // Timestamp Log event timestamp in ISO 8601 format (e.g. // "2026-04-02T12:00:00.000Z"). Timestamp = "timestamp" // Severity Log severity level (e.g. "info", "warn", "error"). Severity = "severity" // LogMessage Human-readable log message describing the event. LogMessage = "message" // ClassName Class name associated with a log event (e.g. exception class or // worker class). ClassName = "class_name" // ServiceName Name of the service or component emitting the log event. ServiceName = "service_name" // GitLabOrganizationID GitLab organization numeric ID. GitLabOrganizationID = "gl_organization_id" // GitLabProjectPath GitLab project path. GitLabProjectPath = "gl_project_path" // EndpointID The endpoint_id of the current endpoint to be passed as caller_id // when calling another service. EndpointID = "endpoint_id" // CallerID The ID of the caller of the current service. CallerID = "caller_id" // RootCallerID The endpoint_id of the original caller at the root of the call // chain. RootCallerID = "root_caller_id" // GitLabSentNotificationID GitLab SentNotification record numeric ID // associated with an incoming email reply. GitLabSentNotificationID = "gl_sent_notification_id" )
Field name constants. Each constant holds the canonical log field name as it appears in structured log output.
Variables ¶
var Deprecated = map[string]DeprecatedField{ "tags.correlation_id": {Standard: CorrelationID, ConstantName: "fields.CorrelationID"}, "user_id": {Standard: GitLabUserID, ConstantName: "fields.GitLabUserID"}, "userid": {Standard: GitLabUserID, ConstantName: "fields.GitLabUserID"}, "extra.user_id": {Standard: GitLabUserID, ConstantName: "fields.GitLabUserID"}, "extra.current_user_id": {Standard: GitLabUserID, ConstantName: "fields.GitLabUserID"}, "meta.user_id": {Standard: GitLabUserID, ConstantName: "fields.GitLabUserID"}, "username": {Standard: GitLabUserName, ConstantName: "fields.GitLabUserName"}, "extra.user": {Standard: GitLabUserName, ConstantName: "fields.GitLabUserName"}, "meta.user": {Standard: GitLabUserName, ConstantName: "fields.GitLabUserName"}, "error": {Standard: ErrorMessage, ConstantName: "fields.ErrorMessage"}, "err": {Standard: ErrorMessage, ConstantName: "fields.ErrorMessage"}, "error.message": {Standard: ErrorMessage, ConstantName: "fields.ErrorMessage"}, "exception.message": {Standard: ErrorMessage, ConstantName: "fields.ErrorMessage"}, "graphql_errors": {Standard: ErrorMessage, ConstantName: "fields.ErrorMessage"}, "status_code": {Standard: HTTPStatusCode, ConstantName: "fields.HTTPStatusCode"}, "extra.status": {Standard: HTTPStatusCode, ConstantName: "fields.HTTPStatusCode"}, "status_text": {Standard: HTTPStatusCode, ConstantName: "fields.HTTPStatusCode"}, "http_status": {Standard: HTTPStatusCode, ConstantName: "fields.HTTPStatusCode"}, "req_url": {Standard: HTTPURL, ConstantName: "fields.HTTPURL"}, "duration": {Standard: DurationS, ConstantName: "fields.DurationS"}, "duration_ms": {Standard: DurationS, ConstantName: "fields.DurationS"}, "elapsed_time": {Standard: DurationS, ConstantName: "fields.DurationS"}, "actual_duration": {Standard: DurationS, ConstantName: "fields.DurationS"}, "time_ms": {Standard: DurationS, ConstantName: "fields.DurationS"}, "total_time": {Standard: DurationS, ConstantName: "fields.DurationS"}, "gitaly.duration": {Standard: DurationS, ConstantName: "fields.DurationS"}, "ip": {Standard: RemoteIP, ConstantName: "fields.RemoteIP"}, "source_ip": {Standard: RemoteIP, ConstantName: "fields.RemoteIP"}, "ip_address": {Standard: RemoteIP, ConstantName: "fields.RemoteIP"}, "hostname": {Standard: HTTPHost, ConstantName: "fields.HTTPHost"}, "request_host": {Standard: HTTPHost, ConstantName: "fields.HTTPHost"}, "gitlab_host": {Standard: HTTPHost, ConstantName: "fields.HTTPHost"}, "kubernetes.host": {Standard: HTTPHost, ConstantName: "fields.HTTPHost"}, "extra.project_id": {Standard: GitLabProjectID, ConstantName: "fields.GitLabProjectID"}, "meta.project_id": {Standard: GitLabProjectID, ConstantName: "fields.GitLabProjectID"}, "meta.search.project_id": {Standard: GitLabProjectID, ConstantName: "fields.GitLabProjectID"}, "job_project_id": {Standard: GitLabProjectID, ConstantName: "fields.GitLabProjectID"}, "target_project_id": {Standard: GitLabProjectID, ConstantName: "fields.GitLabProjectID"}, "extra.pipeline_id": {Standard: GitLabPipelineID, ConstantName: "fields.GitLabPipelineID"}, "meta.pipeline_id": {Standard: GitLabPipelineID, ConstantName: "fields.GitLabPipelineID"}, "root_pipeline_id": {Standard: GitLabPipelineID, ConstantName: "fields.GitLabPipelineID"}, "start_time": {Standard: Timestamp, ConstantName: "fields.Timestamp"}, "level": {Standard: Severity, ConstantName: "fields.Severity"}, "msg": {Standard: LogMessage, ConstantName: "fields.LogMessage"}, "custom_message": {Standard: LogMessage, ConstantName: "fields.LogMessage"}, "extra.message": {Standard: LogMessage, ConstantName: "fields.LogMessage"}, "fields.message": {Standard: LogMessage, ConstantName: "fields.LogMessage"}, "graphql.message": {Standard: LogMessage, ConstantName: "fields.LogMessage"}, "reason": {Standard: LogMessage, ConstantName: "fields.LogMessage"}, "color_message": {Standard: LogMessage, ConstantName: "fields.LogMessage"}, "exception.gitaly": {Standard: LogMessage, ConstantName: "fields.LogMessage"}, "class": {Standard: ClassName, ConstantName: "fields.ClassName"}, "author_class": {Standard: ClassName, ConstantName: "fields.ClassName"}, "exception.class": {Standard: ClassName, ConstantName: "fields.ClassName"}, "extra.class": {Standard: ClassName, ConstantName: "fields.ClassName"}, "extra.class_name": {Standard: ClassName, ConstantName: "fields.ClassName"}, "service": {Standard: ServiceName, ConstantName: "fields.ServiceName"}, "grpc.service_name": {Standard: ServiceName, ConstantName: "fields.ServiceName"}, "auth_service": {Standard: ServiceName, ConstantName: "fields.ServiceName"}, "component": {Standard: ServiceName, ConstantName: "fields.ServiceName"}, "subcomponent": {Standard: ServiceName, ConstantName: "fields.ServiceName"}, "organization_id": {Standard: GitLabOrganizationID, ConstantName: "fields.GitLabOrganizationID"}, "project_path": {Standard: GitLabProjectPath, ConstantName: "fields.GitLabProjectPath"}, "full_path": {Standard: GitLabProjectPath, ConstantName: "fields.GitLabProjectPath"}, "root_pipeline_project_path": {Standard: GitLabProjectPath, ConstantName: "fields.GitLabProjectPath"}, "requested_project_path": {Standard: GitLabProjectPath, ConstantName: "fields.GitLabProjectPath"}, "auth_project_path": {Standard: GitLabProjectPath, ConstantName: "fields.GitLabProjectPath"}, "extra.gl_project_path": {Standard: GitLabProjectPath, ConstantName: "fields.GitLabProjectPath"}, }
Deprecated maps deprecated log field name strings to their canonical replacements. Consumers should use this map to validate field names in their codebase and suggest migrations to the standardised constants defined in this package.
var VariantVersion = map[string]int{ CorrelationID: 1, GitLabUserID: 1, GitLabUserName: 1, DuoWorkflowDefinition: 0, DuoWorkflowID: 0, ErrorType: 0, ErrorMessage: 1, HTTPStatusCode: 1, HTTPMethod: 0, HTTPURL: 0, DurationS: 1, RemoteIP: 1, TCPAddress: 0, HTTPURI: 0, HTTPHost: 0, HTTPProto: 0, RemoteAddr: 0, HTTPReferrer: 0, HTTPUserAgent: 0, WrittenBytes: 0, ContentType: 0, TTFBS: 0, GitLabProjectID: 1, GitLabPipelineID: 1, GitLabNamespaceID: 0, GitLabRootNamespaceID: 0, Timestamp: 0, Severity: 0, LogMessage: 1, ClassName: 0, ServiceName: 0, GitLabOrganizationID: 1, GitLabProjectPath: 1, EndpointID: 0, CallerID: 1, RootCallerID: 0, GitLabSentNotificationID: 0, }
VariantVersion maps each canonical field name to its logging field variant version. A version of 0 means the field is not yet assigned to any variant.
Functions ¶
This section is empty.
Types ¶
type DeprecatedField ¶
type DeprecatedField struct {
// Standard is the canonical field value (e.g. "gl_user_id").
Standard string
// ConstantName is the Go constant to reference in source (e.g. "fields.GitLabUserID").
ConstantName string
}
DeprecatedField describes a deprecated log field name and its canonical replacement.
type ServiceMapping ¶ added in v2.28.0
type ServiceMapping struct {
// contains filtered or unexported fields
}
ServiceMapping carries the per-service variant settings (schema version and dual-emit target) used by ServiceMapping.AppendDeprecated and ServiceMapping.AppendDeprecatedDual when deciding whether to emit a field under its deprecated alias, its standard name, or both.
A ServiceMapping is read-only after construction and safe for concurrent use. The intended pattern is to assign it to a package-level var at boot and share it across goroutines.
The zero value is valid (schema version and dual-emit target of 0); all methods are nil-safe so callers can pass a nil *ServiceMapping during tests or migrations.
Example ¶
ExampleServiceMapping demonstrates a service that is mid-migration: it still emits duration_ms (the deprecated alias) but is ready to switch to duration_s once the admin setting flips the schema version. The mapping is built once at startup with the resolved variant settings and then shared across goroutines.
package main
import (
"bytes"
"context"
"fmt"
"log/slog"
"gitlab.com/gitlab-org/labkit/v2/fields"
)
func main() {
serviceFields := fields.NewServiceMapping(
fields.WithSchemaVersion(0),
fields.WithDualEmitTarget(1),
)
attrs := make([]slog.Attr, 0, 4)
attrs = append(attrs, slog.String(fields.CorrelationID, "req-abc-123"))
attrs = serviceFields.AppendDeprecatedDual(attrs, "duration_ms",
slog.Float64Value(32.0),
slog.Float64Value(0.032),
)
buf := &bytes.Buffer{}
logger := slog.New(slog.NewTextHandler(buf, &slog.HandlerOptions{
// Strip built-in slog keys (time, level, msg) so the Output comment
// only shows the application fields and remains deterministic.
ReplaceAttr: func(_ []string, a slog.Attr) slog.Attr {
if a.Key == slog.TimeKey || a.Key == slog.LevelKey || a.Key == slog.MessageKey {
return slog.Attr{}
}
return a
},
}))
logger.LogAttrs(context.Background(), slog.LevelInfo, "request handled", attrs...)
fmt.Print(buf.String())
}
Output: correlation_id=req-abc-123 duration_ms=32 duration_s=0.032
func NewServiceMapping ¶ added in v2.28.0
func NewServiceMapping(opts ...ServiceMappingOption) *ServiceMapping
NewServiceMapping builds a ServiceMapping from the supplied options.
func (*ServiceMapping) AppendDeprecated ¶ added in v2.28.0
func (m *ServiceMapping) AppendDeprecated(dst []slog.Attr, alias string, value slog.Value) []slog.Attr
AppendDeprecated appends a slog attribute for a logging field that the service still emits under its deprecated alias. The call site keys the attribute by the deprecated name it already uses; labkit resolves the standard name from Deprecated internally.
Behaviour:
- If alias is not a key of Deprecated, append it as-given. This lets service-local field names — those not part of the labkit schema — pass through unchanged.
- Otherwise resolve standard = Deprecated[alias].Standard and dispatch on VariantVersion: emit under standard when the variant version is met, otherwise emit under alias, with dual emit applied when configured.
The value is taken as a slog.Value rather than any so callers can pass typed values (slog.Float64Value, slog.IntValue, …) and avoid the heap allocation that boxing a concrete type into an interface would incur.
Nil-safe.
func (*ServiceMapping) AppendDeprecatedDual ¶ added in v2.28.0
func (m *ServiceMapping) AppendDeprecatedDual(dst []slog.Attr, alias string, legacyValue, standardValue slog.Value) []slog.Attr
AppendDeprecatedDual is the dual-value variant of ServiceMapping.AppendDeprecated. Use when the standard carries a different VALUE than the alias, e.g. duration_ms (milliseconds) → duration_s (seconds).
Nil-safe.
type ServiceMappingOption ¶ added in v2.28.0
type ServiceMappingOption func(*ServiceMapping)
ServiceMappingOption configures a ServiceMapping at construction time.
func WithDualEmitTarget ¶ added in v2.28.0
func WithDualEmitTarget(v int) ServiceMappingOption
WithDualEmitTarget enables dual emission up to variant version v: any field whose VariantVersion is less than or equal to v AND greater than the configured schema version is emitted under both its deprecated alias and its standard name. A value of 0 disables dual emission.
Mirrors the GitLab admin setting `logging_field_dual_emit_target`. Useful during migration windows to populate the new field while downstream consumers catch up, without losing the old one.
func WithSchemaVersion ¶ added in v2.28.0
func WithSchemaVersion(v int) ServiceMappingOption
WithSchemaVersion pins the logging field schema version for the mapping. Fields whose VariantVersion is less than or equal to v are emitted under their standard name; fields above v are emitted under their deprecated alias instead.
Mirrors the GitLab admin setting `logging_field_schema_version`.