diff --git a/lib/contextual_logging/logstash_message_formatter.rb b/lib/contextual_logging/logstash_message_formatter.rb index 1f9f97a..a7017e2 100644 --- a/lib/contextual_logging/logstash_message_formatter.rb +++ b/lib/contextual_logging/logstash_message_formatter.rb @@ -1,11 +1,46 @@ module ContextualLogging class LogstashMessageFormatter + MAX_MESSAGE_LENGTH = 2000 + def format(severity, message, extra_context) - msg_hash = HashWithIndifferentAccess.new('message' => message, 'log_level' => severity) - logstash_data = extra_context.merge(msg_hash) + if severity == 'INFO' + truncated_message = truncate(message) + limited_extra_context = truncate_log_extra_context(extra_context) + else + truncated_message = message + limited_extra_context = extra_context + end + + logstash_data = HashWithIndifferentAccess.new( + 'message' => truncated_message, + 'log_level' => severity + ).merge(limited_extra_context) + logstash_event = LogStash::Event.new(logstash_data) logstash_event.to_json end + + private + + def truncate(message) + message[0...MAX_MESSAGE_LENGTH] + end + + def truncate_log_extra_context(extra_context) + extra_context.each_with_object(HashWithIndifferentAccess.new) do |(key, value), limited_extra_context| + if value.is_a?(Hash) + limited_extra_context[key] = HashWithIndifferentAccess.new + value.each do |k, v| + if v.is_a?(String) + limited_extra_context[key][k] = truncate(v) + else + limited_extra_context[key][k] = truncate(v.inspect) + end + end + else + limited_extra_context[key] = value + end + end + end end end - diff --git a/spec/contextual_logging_spec.rb b/spec/contextual_logging_spec.rb index 1963fdb..e4db045 100644 --- a/spec/contextual_logging_spec.rb +++ b/spec/contextual_logging_spec.rb @@ -1,4 +1,22 @@ require 'spec_helper' -describe ContextualLogging do +describe ContextualLogging::LogstashMessageFormatter do + message_formatter = ContextualLogging::LogstashMessageFormatter.new + it 'should limit message size to 2000 characters when severity level is INFO' do + message = (0...3000).map { ('a'..'z').to_a[rand(26)] }.join + log_message = message_formatter.format('INFO', message, {}) + expect(JSON[log_message]['message'].length).to equal 2000 + end + + it 'should limit extra context values that are two levels deep to 2000 characters when severity level is INFO' do + message = (0...3000).map { ('a'..'z').to_a[rand(26)] }.join + extra_context = HashWithIndifferentAccess.new + extra_context['params'] = HashWithIndifferentAccess.new(nodes: {}) + extra_context['text'] = (0...3000).map { ('a'..'z').to_a[rand(26)] }.join + extra_context['params']['nodes']['a'] = (0...3000).map { ('a'..'z').to_a[rand(26)] }.join + + log_message = message_formatter.format('INFO', message, extra_context) + expect(JSON[log_message]['params']['nodes'].length).to equal 2000 + expect(JSON[log_message]['text'].length).to equal 3000 + end end