# frozen_string_literal: true require_relative '../test_helper' require 'logster/message' class TestMessage < MiniTest::Test def test_merge_similar msg1 = Logster::Message.new(0, '', 'test', 10) msg1.populate_from_env(a: "1", b: "2") msg2 = Logster::Message.new(0, '', 'test', 20) msg2.populate_from_env(a: "2", c: "3") assert_equal(msg2.grouping_key, msg1.grouping_key) msg1.merge_similar_message(msg2) assert_equal(20, msg1.timestamp) assert_equal(10, msg1.first_timestamp) assert_equal(msg1.env_buffer, [msg2.env]) end def test_populate_from_env_will_add_time_to_env_unless_it_already_exists t = (Time.now.to_f * 1000).to_i msg = Logster::Message.new(0, '', 'test', t) msg.populate_from_env({}) assert_equal(t, msg.env["time"]) msg = Logster::Message.new(0, '', 'test', t) msg.populate_from_env(time: 5) assert_nil(msg.env["time"]) assert_equal(5, msg.env[:time]) msg = Logster::Message.new(0, '', 'test', t) msg.populate_from_env("time" => 6) assert_equal(6, msg.env["time"]) assert_nil(msg.env[:time]) msg = Logster::Message.new(0, '', 'test', t) msg.populate_from_env([{ "time" => 6 }, { "time" => 8 }]) assert_equal([6, 8], msg.env.map { |e| e["time"] }) assert_equal([nil, nil], msg.env.map { |e| e[:time] }) msg = Logster::Message.new(0, '', 'test', t) msg.populate_from_env([{ dsd: 6 }, { dsd: 8 }]) assert_equal([t, t], msg.env.map { |e| e["time"] }) end def test_merge_messages_both_with_array_envs msg1 = Logster::Message.new(0, '', 'test', 10) msg1.env = [{ a: "aa", b: "bb" }, { c: "cc", d: "dd" }] msg2 = Logster::Message.new(0, '', 'test', 20) msg2.env = [{ e: "ee", f: "ff" }, { g: "gg", h: "hh" }] msg1.merge_similar_message(msg2) assert_equal(msg2.env, msg1.env_buffer) end def test_merge_messages_one_with_array_envs msg1 = Logster::Message.new(0, '', 'test', 10) msg1.env = { e: "ee", f: "ff" } msg2 = Logster::Message.new(0, '', 'test', 20) msg2.env = [{ a: "aa", b: "bb" }, { c: "cc", d: "dd" }] msg1.merge_similar_message(msg2) assert_equal(msg2.env, msg1.env_buffer) end def test_adds_application_version Logster.config.application_version = "abc" msg = Logster::Message.new(0, '', 'test', 10) msg.populate_from_env({}) assert_equal("abc", msg.env["application_version"]) ensure Logster.config.application_version = nil end def test_use_full_hostname Logster::Message.instance_variable_set(:@hostname, nil) Logster.config.use_full_hostname = true msg = Logster::Message.new(0, '', 'test', 10) msg.populate_from_env({}) assert_equal(`hostname -f`.strip!, msg.env["hostname"]) ensure Logster.config.use_full_hostname = nil Logster::Message.instance_variable_set(:@hostname, nil) end def test_merging_sums_count_for_both_messages msg1 = Logster::Message.new(0, '', 'test', 10, count: 15) msg2 = Logster::Message.new(0, '', 'test', 20, count: 13) msg2.env = {} assert_equal(msg1.grouping_key, msg2.grouping_key) msg1.merge_similar_message(msg2) assert_equal(msg1.count, 15 + 13) end def test_messages_with_bad_encoding_dont_break_logster hash = { severity: 0, progname: "test", message: "invalid encoding", env: { a: "bad_value", b: ["bad_value"] } } json = hash.to_json.gsub("bad_value", "45\xC0\xBE") message = Logster::Message.from_json(json) message.to_json # test failure would be this raising exception message.env = JSON.parse(json)["env"] message.to_json end def test_populate_from_env_works_on_array msg = Logster::Message.new(0, '', 'test', 10) hash = { "custom_key" => "key" } msg.populate_from_env([hash]) assert Array === msg.env assert_equal(msg.env.size, 1) assert hash <= msg.env[0] end def test_merging_envs_add_new_envs_to_buffer msg1 = Logster::Message.new(0, '', 'test', 10, count: 50) msg1.env = 50.times.map { |n| { a: n } } msg2 = Logster::Message.new(0, '', 'test', 20, count: 13) msg2.env = 13.times.map { |n| { b: n } } assert_equal(msg1.grouping_key, msg2.grouping_key) msg1.merge_similar_message(msg2) assert_equal(63, msg1.count) # update count assert_equal(msg2.env, msg1.env_buffer) end def test_message_to_h_respects_params msg = Logster::Message.new(0, "", "test") test_hash = { test_key: "this is a test" } msg.env = test_hash assert_equal(test_hash, msg.to_h[:env]) assert_nil(msg.to_h(exclude_env: true)[:env]) end def test_message_to_json_respects_params msg = Logster::Message.new(0, "", "test") test_hash = { test_key: "this is a test" } msg.env = test_hash assert_includes(msg.to_json, test_hash.to_json) refute_includes(msg.to_json(exclude_env: true), test_hash.to_json) end def test_drop_redundant_envs message = Logster::Message.new(Logger::WARN, '', 'message') message.env = [{ a: 4 }] * 10 assert_equal(10, message.env.size) message.drop_redundant_envs(5) assert_equal(5, message.env.size) env = { f: 5, g: 4 } message.env = env.dup message.drop_redundant_envs(1) assert_equal(env, message.env) end def test_apply_env_size_limit_keeps_as_many_keys_as_possible message = Logster::Message.new(Logger::WARN, '', 'message', 1) env = { a: 1, bb: 22, ccc: 333 } message.env = env.dup message.apply_env_size_limit(24) assert_operator(message.env.to_json.bytesize, :<=, 24) assert_equal({ a: 1, bb: 22 }.to_json.bytesize, message.env.to_json.bytesize) message.env = [env.dup] * 5 message.apply_env_size_limit(24) assert_equal(5, message.env.size) message.env.each do |e| assert_operator(e.to_json.bytesize, :<=, 24) assert_equal({ a: 1, bb: 22 }.to_json.bytesize, e.to_json.bytesize) end message.env = env.dup message.apply_env_size_limit(25) assert_operator(message.env.to_json.bytesize, :<=, 25) assert_equal({ a: 1, bb: 22, ccc: 333 }.to_json.bytesize, message.env.to_json.bytesize) end def test_apply_message_size_limit_removes_gems_dir_from_backtrace_to_keep_total_message_size_below_limit backtrace = <<~TEXT /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rails_multisite-2.0.7/lib/rails_multisite/connection_management.rb:220:in `with_connection' /var/www/discourse/vendor/bundle/ruby/2.6.0/gems/rails_multisite-2.0.7/lib/rails_multisite/connection_management.rb:60:in `with_connection' /var/www/discourse/lib/scheduler/defer.rb:89:in `do_work' /var/www/discourse/lib/scheduler/defer.rb:79:in `block (2 levels) in start_thread' TEXT without_gems_dir = <<~TEXT rails_multisite-2.0.7/lib/rails_multisite/connection_management.rb:220:in `with_connection' rails_multisite-2.0.7/lib/rails_multisite/connection_management.rb:60:in `with_connection' /var/www/discourse/lib/scheduler/defer.rb:89:in `do_work' /var/www/discourse/lib/scheduler/defer.rb:79:in `block (2 levels) in start_thread' TEXT gems_dir = "/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/" message = Logster::Message.new(Logger::WARN, '', 'message', 1) message.backtrace = backtrace.dup assert_operator(message.to_json(exclude_env: true).bytesize, :>=, 500) message.apply_message_size_limit(500, gems_dir: gems_dir) assert_operator(message.to_json(exclude_env: true).bytesize, :<=, 500) assert_equal(without_gems_dir.strip, message.backtrace.strip) end def test_apply_message_size_limit_removes_lines_from_backtrace_to_keep_total_size_below_limit backtrace = <<~TEXT rails_multisite-2.0.7/lib/rails_multisite/connection_management.rb:220:in `with_connection' rails_multisite-2.0.7/lib/rails_multisite/connection_management.rb:60:in `with_connection' /var/www/discourse/lib/scheduler/defer.rb:89:in `do_work' /var/www/discourse/lib/scheduler/defer.rb:79:in `block (2 levels) in start_thread' TEXT expected = <<~TEXT rails_multisite-2.0.7/lib/rails_multisite/connection_management.rb:220:in `with_connection' rails_multisite-2.0.7/lib/rails_multisite/connection_management.rb:60:in `with_connection' /var/www/discourse TEXT message = Logster::Message.new(Logger::WARN, '', 'message', 1) message.backtrace = backtrace.dup assert_operator(message.to_json(exclude_env: true).bytesize, :>=, 350) message.apply_message_size_limit(350) assert_operator(message.to_json(exclude_env: true).bytesize, :<=, 350) assert_equal(expected.strip, message.backtrace.strip) end def test_truncate_backtrace_shouldnt_corrupt_backtrace_when_it_contains_multibytes_characters backtrace = "aहa" message = Logster::Message.new(Logger::WARN, '', 'message', 1) message.backtrace = backtrace.dup message.truncate_backtrace(3) assert_equal("a", message.backtrace) message.backtrace = backtrace.dup message.truncate_backtrace(4) assert_equal("aह", message.backtrace) message.backtrace = backtrace.dup message.truncate_backtrace(5) assert_equal(backtrace, message.backtrace) end def test_apply_message_size_limit_doesnt_remove_backtrace_entirely message = Logster::Message.new(Logger::WARN, '', 'message', 1) message.backtrace = "a" * 1000 assert_operator(message.to_json(exclude_env: true).bytesize, :>=, 500) message.apply_message_size_limit(500) assert_operator(message.to_json(exclude_env: true).bytesize, :<=, 500) assert_equal(("a" * 354).size, message.backtrace.size) end def test_apply_message_size_limit_doesnt_hang_forever_and_doesnt_remove_backtrace_entirely message = Logster::Message.new(Logger::WARN, '', 'message', 1) message.backtrace = "aa" * 100 message.apply_message_size_limit(10) assert_equal(("aa" * 100).size, message.backtrace.size) end end