Verified Commit ef55ba01 authored by Sean McGivern's avatar Sean McGivern 🔴
Browse files

Allow converting a context to headers

`Labkit::Context#to_headers` works like `#to_h`, but:

1. Excludes the correlation ID (which will already be set in another
   header).
2. Has keys suitable for use in HTTP headers, prefixed with
   `Labkit::Context::HEADER_PREFIX`. Because the keys go through
   `.log_key`, this means it will mostly be `X-Gitlab-Meta-` as a
   prefix.
parent 6cf38f1a
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ module Labkit
    LOG_KEY = "meta"
    CORRELATION_ID_KEY = "correlation_id"
    RAW_KEYS = [CORRELATION_ID_KEY].freeze
    HEADER_PREFIX = "X-Gitlab-"
    KNOWN_KEYS = %w[user project root_namespace subscription_plan caller_id
                    related_class feature_category].freeze

@@ -67,6 +68,10 @@ module Labkit
        @known_log_keys ||= (KNOWN_KEYS.map(&method(:log_key)) + RAW_KEYS).freeze
      end

      def header_name(name)
        HEADER_PREFIX + log_key(name).titlecase(keep_id_suffix: true).gsub(/\W/, "-")
      end

      private

      def contexts
@@ -95,6 +100,12 @@ module Labkit
      data[CORRELATION_ID_KEY]
    end

    def to_headers
      to_h.except(CORRELATION_ID_KEY).transform_keys do |key|
        self.class.header_name(key)
      end
    end

    protected

    def assign_attributes(attributes)
+45 −0
Original line number Diff line number Diff line
@@ -107,6 +107,25 @@ describe Labkit::Context do
    end
  end

  describe ".header_name" do
    using RSpec::Parameterized::TableSyntax

    where(:value, :result) do
      :caller_id | "X-Gitlab-Meta-Caller-Id"
      :root_namespace | "X-Gitlab-Meta-Root-Namespace"
      :user | "X-Gitlab-Meta-User"
      :unknown | "X-Gitlab-Meta-Unknown"
      "meta.user" | "X-Gitlab-Meta-User"
      described_class::CORRELATION_ID_KEY | "X-Gitlab-Correlation-Id"
    end

    with_them do
      it do
        expect(described_class.header_name(value)).to eq(result)
      end
    end
  end

  describe "#to_h" do
    let(:expected_hash) do
      log_hash(user: "user",
@@ -159,6 +178,32 @@ describe Labkit::Context do
    end
  end

  describe "#to_headers" do
    it "returns a hash of header names to values, excluding correlation ID" do
      context = described_class.new(
        user: -> { "user" },
        root_namespace: -> { "namespace" },
        project: -> { "project" },
        caller_id: "ProjectsController#show",
      )

      expect(context.to_headers).to include("X-Gitlab-Meta-User" => "user",
                                            "X-Gitlab-Meta-Root-Namespace" => "namespace",
                                            "X-Gitlab-Meta-Project" => "project",
                                            "X-Gitlab-Meta-Caller-Id" => "ProjectsController#show")
    end

    it "does not include empty values" do
      context = described_class.new(
        user: -> { },
        root_namespace: nil,
        project: "",
      )

      expect(context.to_headers).to be_empty
    end
  end

  describe "#initialize" do
    it "assigns only known keys as strings" do
      context = described_class.new(