Commit afa03840 authored by Matthias Käppler's avatar Matthias Käppler 3️⃣ Committed by Bob Van Landuyt
Browse files

Reject reserved log keys in dev & test

parent 08ca2edf
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
@@ -6,6 +6,17 @@ require "json"
module Labkit
  module Logging
    class JsonLogger < ::Logger
      INTERNAL_LOG_KEYS = Labkit::Context::RAW_KEYS + [Labkit::Context::LOG_KEY]
      RESERVED_LOG_KEYS = INTERNAL_LOG_KEYS.map(&:to_sym) + [
        :environment,
        :host,
        :shard,
        :stage,
        :subcomponent,
        :tier,
        :type,
      ].freeze

      def self.log_level(fallback: ::Logger::DEBUG)
        ENV.fetch("GITLAB_LOG_LEVEL", fallback)
      end
@@ -24,6 +35,7 @@ module Labkit
        when String
          data[:message] = message
        when Hash
          reject_reserved_log_keys!(message)
          data.merge!(message)
        end

@@ -39,6 +51,16 @@ module Labkit
      def dump_json(data)
        JSON.generate(data)
      end

      def reject_reserved_log_keys!(hash)
        return if ENV["RAILS_ENV"] == "production"

        reserved_keys_used = hash.transform_keys(&:to_sym).slice(*RESERVED_LOG_KEYS)
        if reserved_keys_used.any?
          raise "The following log keys used are reserved: #{reserved_keys_used.keys.join(", ")}" +
                  "\n\nUse key names that are descriptive e.g. by using a prefix."
        end
      end
    end
  end
end
+51 −0
Original line number Diff line number Diff line
@@ -120,4 +120,55 @@ RSpec.describe Labkit::Logging::JsonLogger do
    expect(data["message"]).to be_nil
    expect(data["correlation_id"]).to eq("new-correlation-id")
  end

  it "uses indifferent log key access" do
    output = subject.format_message("INFO", now, "test", { hello: 1, "world": 2 })
    data = JSON.parse(output)

    expect(data["hello"]).to eq(1)
    expect(data["world"]).to eq(2)
  end

  describe "reserved log keys" do
    let(:reserved_key_data) { described_class::RESERVED_LOG_KEYS.to_h { |k| [k, 42] } }
    let(:expected_error) { /^The following log keys used are reserved: #{described_class::RESERVED_LOG_KEYS.join(", ")}.*/ }

    shared_examples "raise error" do
      it "raises an error" do
        expect { subject.format_message("INFO", now, "test", reserved_key_data) }.to raise_error(expected_error)
      end

      describe "symbol and string indifference" do
        it "raises error when reserved key is a symbol" do
          expect { subject.format_message("INFO", now, "test", reserved_key_data.transform_keys(&:to_sym)) }.to raise_error(expected_error)
        end

        it "raises error when reserved key is a string" do
          expect { subject.format_message("INFO", now, "test", reserved_key_data.transform_keys(&:to_s)) }.to raise_error(expected_error)
        end
      end
    end

    describe "in test env" do
      it_behaves_like "raise error"
    end

    describe "in dev env" do
      before do
        stub_env("RAILS_ENV", "development")
      end

      it_behaves_like "raise error"
    end

    describe "in production env" do
      before do
        stub_env("RAILS_ENV", "production")
      end

      it "does not raise an error" do
        expect { subject.format_message("INFO", now, "test", reserved_key_data) }.not_to raise_error
      end
    end
  end
end