Commit 2f64d944 authored by Doug Barrett's avatar Doug Barrett 🔴
Browse files

feat(fields): Add deprecated field mappings module

Add Labkit::Fields::Deprecated module that maps deprecated logging field
names to their standardized replacements. This supports the Observability
Field Standardisation initiative.

The module provides:
- `all` - returns list of all deprecated field names
- `standard_field_for(deprecated)` - returns the standard field name
- `deprecated?(field)` - checks if a field is deprecated

Also adds `constant_name_for` helper to Labkit::Fields for reverse
lookup of field constants by value.

See: https://handbook.gitlab.com/handbook/engineering/architecture/design-documents/observability_field_standardisation/
parent d6eb679b
Loading
Loading
Loading
Loading
+73 −2
Original line number Diff line number Diff line
@@ -5,7 +5,7 @@ module Labkit
  # Fields is intended to be a SSOT for all of the common field names that
  # we emit via any observability we add to our systems.
  #
  # These fields should span multiple services. This is
  # These fields should span multiple services.
  #
  # The goal of this package is to reduce the likelihood for typos or
  # subtly different naming conventions. This will help to ensure we
@@ -30,7 +30,6 @@ module Labkit
  module Fields
    # correlation_id - string
    #
    # correlation_id - string
    # This field is used to correlate
    # the logs emitted by all of our systems.
    # This should be present in all log line
@@ -50,5 +49,77 @@ module Labkit
    # should clearly indicate what the intended use of the
    # field is and should be replicated across the labkit
    # variations.

    # Get all standard field constants
    def self.standard_fields
      constants(false)
        .reject { |c| c == :Deprecated }
        .map { |c| const_get(c) }
        .select { |v| v.is_a?(String) }
    end

    # Get the constant name for a field value
    # @param field_value [String] The field value (e.g., "gl_user_id")
    # @return [String, nil] The constant name (e.g., "GL_USER_ID") or nil if not found
    def self.constant_name_for(field_value)
      constants(false).find do |const_name|
        next if const_name == :Deprecated

        const_get(const_name) == field_value
      end&.to_s
    end

    module Deprecated
      # This module tracks deprecated field names and maps them to their
      # standard replacements. These mappings are used by the field scanner
      # to identify and track usage of deprecated fields in the codebase.

      MAPPINGS = {
        Fields::GL_USER_ID => ["meta.user_id"],
      }.freeze

      class << self
        # Get all deprecated fields
        #
        # @return [Array<String>] List of all deprecated field names
        def all
          MAPPINGS.values.flatten
        end

        # Check if a field is deprecated
        #
        # @param field_name [String, Symbol] The field name to check
        # @return [Boolean] true if the field is deprecated
        def deprecated?(field_name)
          all.include?(field_name.to_s)
        end

        # Get the standard field for a deprecated field
        #
        # @param deprecated_field [String, Symbol] The deprecated field name
        # @return [String, nil] The standard field name, or nil if not found
        def standard_field_for(deprecated_field)
          MAPPINGS.each do |standard, deprecated_list|
            return standard if deprecated_list.include?(deprecated_field.to_s)
          end
          nil
        end

        # Get all deprecated fields for a standard field
        #
        # @param standard_field [String] The standard field name
        # @return [Array<String>] List of deprecated field names
        def deprecated_for(standard_field)
          MAPPINGS[standard_field] || []
        end

        # Get all mappings
        #
        # @return [Hash] The complete mapping hash
        def mappings
          MAPPINGS
        end
      end
    end
  end
end
+47 −0
Original line number Diff line number Diff line
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Labkit::Fields do
  describe '.standard_fields' do
    it 'returns an array of strings' do
      expect(described_class.standard_fields).to be_an(Array)
      expect(described_class.standard_fields).to all(be_a(String))
    end
  end

  describe Labkit::Fields::Deprecated do
    describe '.all' do
      it 'returns an array of deprecated field names' do
        expect(described_class.all).to be_an(Array)
        expect(described_class.all).to all(be_a(String))
      end
    end

    describe '.deprecated?' do
      it 'returns true for a known deprecated field' do
        result = described_class.deprecated?('meta.user_id')
        expect(result).to be(true)
      end

      it 'returns false for a known standard field' do
        result = described_class.deprecated?(Labkit::Fields::GL_USER_NAME)
        expect(result).to be(false)
      end
    end

    describe '.standard_field_for' do
      it 'returns a standard field for a known deprecated field' do
        result = described_class.standard_field_for('meta.user_id')
        expect(result).to be(Labkit::Fields::GL_USER_ID)
      end
    end

    describe '.mappings' do
      it 'returns a frozen hash' do
        expect(described_class.mappings).to be_a(Hash)
        expect(described_class.mappings).to be_frozen
      end
    end
  end
end