From a9822880b31b558b7858f9d553a4cf7363cd5dfd Mon Sep 17 00:00:00 2001
From: John Harris <john.harris@nexusmods.com>
Date: Tue, 5 Jul 2022 17:11:53 +0100
Subject: [PATCH] feat: appender filter allows tuning logging via env vars

---
 lib/nexus_semantic_logger.rb                 |  1 +
 lib/nexus_semantic_logger/appender_filter.rb | 69 ++++++++++++++++++++
 lib/nexus_semantic_logger/application.rb     | 18 +++--
 3 files changed, 83 insertions(+), 5 deletions(-)
 create mode 100644 lib/nexus_semantic_logger/appender_filter.rb

diff --git a/lib/nexus_semantic_logger.rb b/lib/nexus_semantic_logger.rb
index 552dacb..b7f2a0a 100644
--- a/lib/nexus_semantic_logger.rb
+++ b/lib/nexus_semantic_logger.rb
@@ -1,4 +1,5 @@
 # frozen_string_literal: true
+require 'nexus_semantic_logger/appender_filter'
 require 'nexus_semantic_logger/application'
 require 'nexus_semantic_logger/datadog_formatter'
 
diff --git a/lib/nexus_semantic_logger/appender_filter.rb b/lib/nexus_semantic_logger/appender_filter.rb
new file mode 100644
index 0000000..d27182f
--- /dev/null
+++ b/lib/nexus_semantic_logger/appender_filter.rb
@@ -0,0 +1,69 @@
+# frozen_string_literal: true
+require 'rails_semantic_logger'
+
+module NexusSemanticLogger
+  class AppenderFilter
+    def self.filter_lambda
+      -> (log) {
+        # log API see https://logger.rocketjob.io/log_struct.html
+        # and lib/semantic_logger/levels.rb
+        # level: :trace=>0, :debug=>1, :info=>2, :warn=>3, :error=>4, :fatal=>5
+        current_log_level = SemanticLogger::Levels.index(env_names_default_level)
+
+        # Names allow overriding the level that will be appended,
+        # else the global level is used to determine appending.
+        append = false
+        if log.name.in?(env_names_trace)
+          append = true
+        elsif (log.name.in?(env_names_debug))
+          append = log.level_index >= 1
+        elsif (log.name.in?(env_names_info))
+          append = log.level_index >= 2
+        elsif (log.name.in?(env_names_warn))
+          append = log.level_index >= 3
+        elsif (log.name.in?(env_names_error))
+          append = log.level_index >= 4
+        elsif (log.name.in?(env_names_fatal))
+          append = log.level_index >= 5
+        else
+          append = log.level_index >= current_log_level
+        end
+        append
+      }
+    end
+
+    def self.env_names_default_level
+      @@names_default_level ||= ENV.fetch('LOG_NAMES_DEFAULT_LEVEL', Rails.application.config.log_level)
+    end
+
+    def self.env_names_trace
+      @@names_trace ||= fetch_env_names('LOG_NAMES_TRACE')
+    end
+
+    def self.env_names_debug
+      @@names_debug ||= fetch_env_names('LOG_NAMES_DEBUG')
+    end
+
+    def self.env_names_info
+      @@names_info ||= fetch_env_names('LOG_NAMES_INFO')
+    end
+
+    def self.env_names_warn
+      @@names_warn ||= fetch_env_names('LOG_NAMES_WARN')
+    end
+
+    def self.env_names_error
+      @@names_error ||= fetch_env_names('LOG_NAMES_ERROR')
+    end
+
+    def self.env_names_fatal
+      @@names_fatal ||= fetch_env_names('LOG_NAMES_FATAL')
+    end
+
+    private
+
+    def self.fetch_env_names(var)
+      ENV.fetch(var, '').split(',').to_set
+    end
+  end
+end
diff --git a/lib/nexus_semantic_logger/application.rb b/lib/nexus_semantic_logger/application.rb
index c7b40fb..67314f6 100644
--- a/lib/nexus_semantic_logger/application.rb
+++ b/lib/nexus_semantic_logger/application.rb
@@ -33,7 +33,8 @@ module NexusSemanticLogger
       # Default logging is stdout in datadog compatible JSON.
       config.rails_semantic_logger.format = NexusSemanticLogger::DatadogFormatter.new(service)
       config.rails_semantic_logger.add_file_appender = false
-      config.semantic_logger.add_appender(io: $stdout, formatter: config.rails_semantic_logger.format)
+      dd_appender = config.semantic_logger.add_appender(io: $stdout, formatter: config.rails_semantic_logger.format)
+      dd_appender.filter = NexusSemanticLogger::AppenderFilter.filter_lambda
 
       logger.info('SemanticLogger initialised.', level: config.log_level)
     end
@@ -44,13 +45,19 @@ module NexusSemanticLogger
 
       # Change default logging to coloured logging on stdout.
       config.semantic_logger.clear_appenders!
-      config.semantic_logger.add_appender(io: $stdout, formatter: :color)
+      color_appender = config.semantic_logger.add_appender(io: $stdout, formatter: :color)
+      color_appender.filter = NexusSemanticLogger::AppenderFilter.filter_lambda
+
       if ENV['DD_AGENT_HOST'].present? && ENV['DD_AGENT_PORT'].present?
         # Development logs can be sent to datadog via a TCP logging endpoint on a local agent.
         # Each port is assigned a particular service.
         # See https://logger.rocketjob.io/appenders.html
-        config.semantic_logger.add_appender(appender: :tcp, server: "#{ENV['DD_AGENT_HOST']}:#{ENV['DD_AGENT_PORT']}",
-                                            formatter: config.rails_semantic_logger.format)
+        dd_appender = config.semantic_logger.add_appender(
+          appender: :tcp,
+          server: "#{ENV['DD_AGENT_HOST']}:#{ENV['DD_AGENT_PORT']}",
+          formatter: config.rails_semantic_logger.format
+        )
+        dd_appender.filter = NexusSemanticLogger::AppenderFilter.filter_lambda
       end
 
       logger.info('SemanticLogger initialised in development.', level: config.log_level)
@@ -59,7 +66,8 @@ module NexusSemanticLogger
     def self.test(config)
       # Use human readable coloured output for logs when running tests.
       config.semantic_logger.clear_appenders!
-      config.semantic_logger.add_appender(io: $stdout, formatter: :color)
+      color_appender = config.semantic_logger.add_appender(io: $stdout, formatter: :color)
+      color_appender.filter = NexusSemanticLogger::AppenderFilter.filter_lambda
     end
   end
 end
-- 
GitLab