Loading lib/labkit/logging/json_logger.rb +22 −0 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -24,6 +35,7 @@ module Labkit when String data[:message] = message when Hash reject_reserved_log_keys!(message) data.merge!(message) end Loading @@ -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 spec/labkit/logging/json_logger_spec.rb +51 −0 Original line number Diff line number Diff line Loading @@ -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 Loading
lib/labkit/logging/json_logger.rb +22 −0 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -24,6 +35,7 @@ module Labkit when String data[:message] = message when Hash reject_reserved_log_keys!(message) data.merge!(message) end Loading @@ -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
spec/labkit/logging/json_logger_spec.rb +51 −0 Original line number Diff line number Diff line Loading @@ -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