Commit 2435b0cd authored by Elliot Forbes's avatar Elliot Forbes 2️⃣
Browse files

Merge branch 'dbarrett/field-standardization-adr' into 'master'

Add dynamic runtime linter ADR

See merge request !218

Merged-by: Elliot Forbes's avatarElliot Forbes <eforbes@gitlab.com>
Approved-by: Elliot Forbes's avatarElliot Forbes <eforbes@gitlab.com>
Approved-by: default avatarPeter Leitzen <pleitzen@gitlab.com>
Reviewed-by: default avatarPeter Leitzen <pleitzen@gitlab.com>
Reviewed-by: default avatarGitLab Duo <gitlab-duo@gitlab.com>
Co-authored-by: default avatardbarrett <dbarrett@gitlab.com>
parents 9ada87c9 7c8c5adc
Loading
Loading
Loading
Loading
Loading
+124 −0
Original line number Diff line number Diff line
---
owning-stage: '~devops::developer experience'
description: 'Logging Field Standardization: Dynamic Runtime Linting'
---

# Logging Field Standardization ADR: Dynamic Runtime Linting

## Context

GitLab is implementing a [logging field standardization initiative](https://handbook.gitlab.com/handbook/engineering/architecture/design-documents/observability_field_standardisation/) to ensure logs are queryable and actionable across all systems. We need a mechanism to identify and track deprecated or non-standard logging fields across multiple codebases.

### Requirements

The solution must:

1. Detect deprecated fields at the point of emission (runtime).
1. Provide immediate feedback to developers (shift-left).
1. Prevent new violations without blocking existing work.
1. Support gradual migration from deprecated to standard fields.
1. Never affect production performance.
1. Provide clear guidance on standard field replacements.

### The problem with static analysis

We initially considered RuboCop (static linting), but this approach is inadequate due to Ruby's [dynamic and complex field construction](https://gitlab.com/gitlab-org/gitlab/-/blob/cfd4fb97968d1f7d30f39f89740e414e9437063a/lib/bulk_imports/logger.rb#L46).

Static analysis can't reliably detect:

- Fields merged from hash arguments.
- Dynamically constructed field names.
- Fields passed through multiple abstraction layers.
- Conditional field inclusion based on runtime state.

## Decision

Implement dynamic runtime linting to validate logging fields as they're emitted during development and testing, rather than using static analysis.

The validator will:

- Intercept logging calls at runtime to detect deprecated fields.
- Compare detected violations against a frozen baseline of known violations.
- Raise an error on new violations while ignoring tracked existing tracked violations.
- Provide immediate feedback to developers during local development.
- Never affect production performance.

## Consequences

### Benefits

- **Shift-left feedback**: Developers discover violations during local development, not in code review.
- **Comprehensive detection**: Captures violations from all code execution paths (tests, Rake tasks, console, development environments).
- **Accurate detection**: Runtime interception catches dynamically constructed fields that static analysis misses.
- **Non-blocking**: Existing violations don't prevent development. They're tracked explicitly in baseline.
- **Regression prevention**: CI fails on new violations, preventing deprecated fields from reappearing.
- **Clear guidance**: Exact replacement field suggested for each violation.
- **Zero production impact**: Validation only runs in development and test environments.

### Trade-offs

- **Execution path dependency**: Only detects violations in code paths that execute during the process.
- **Runtime overhead**: Adds interception to all non-production processes.
- **At-exit reporting**: Violations not visible until process completes.
- **Baseline maintenance**: YAML files require updates when violations are fixed or added.
- **Learning curve**: Developers must understand baseline management.
- **File-level scoping**: Multiple violations in the same file are tracked together, making partial fixes during test runs challenging.

### Risks and mitigations

| Risk | Mitigation |
|------|------------|
| Limited code path coverage misses violations | Use Kibana to identify fields in production logs, run comprehensive test suites, use development server testing |
| Baseline drift across branches | Clear documentation, automated baseline regeneration support |
| At-exit reporting missed if process crashes | Violations still prevented in CI where processes complete successfully |

## Alternatives

### Alternative 1: Static analysis with RuboCop

Use custom RuboCop cops to detect deprecated field usage.

Rejected because:

- Can't handle fields merged from hash variables.
- Would produce many false negatives.
- Complex pattern matching still misses dynamic cases.
- Poor developer experience with unclear violations.

### Alternative 2: Manual tracking

Track violations in spreadsheets or GitLab issues.

Rejected because:

- No automated enforcement or detection.
- Manual process becomes stale quickly.
- No shift-left feedback to developers.
- Can't prevent regressions.

### Alternative 3: Grep-based CI checks

Search source code for deprecated field strings in CI.

Rejected because:

- High false positive rate (matches in comments, strings, tests).
- Can't distinguish field usage from definitions.
- No stable tracking across refactoring.
- Poor user experience with unclear error messages.

### Alternative 4: Production log analysis only

Rely solely on Kibana analysis to find deprecated fields.

Rejected because:

- No prevention, only reactive detection.
- Violations already in production when discovered.
- No developer feedback during development.
- Difficult to trace back to specific code locations.

## References

- [Parent Epic](https://gitlab.com/groups/gitlab-org/quality/-/work_items/235)
- [Observability Field Standardisation](https://handbook.gitlab.com/handbook/engineering/architecture/design-documents/observability_field_standardisation/)