From 6100464e04b03b75a2e82729b9b94f2ff2426904 Mon Sep 17 00:00:00 2001 From: John Harris <john.harris@nexusmods.com> Date: Tue, 5 Jul 2022 12:30:31 +0100 Subject: [PATCH] feat: initial version --- README.md | 2 + lib/nexus_semantic_logger.rb | 6 ++ lib/nexus_semantic_logger/application.rb | 65 +++++++++++++++++++ .../datadog_formatter.rb | 38 +++++++++++ nexus_semantic_logger.gemspec | 15 +++-- 5 files changed, 120 insertions(+), 6 deletions(-) create mode 100644 lib/nexus_semantic_logger.rb create mode 100644 lib/nexus_semantic_logger/application.rb create mode 100644 lib/nexus_semantic_logger/datadog_formatter.rb diff --git a/README.md b/README.md index 0ba0133..42c42f4 100644 --- a/README.md +++ b/README.md @@ -1 +1,3 @@ # nexus_semantic_logger + +Configures a [semantic_logger](https://rubygems.org/gems/rails_semantic_logger) as required for NexusMods components. diff --git a/lib/nexus_semantic_logger.rb b/lib/nexus_semantic_logger.rb new file mode 100644 index 0000000..552dacb --- /dev/null +++ b/lib/nexus_semantic_logger.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true +require 'nexus_semantic_logger/application' +require 'nexus_semantic_logger/datadog_formatter' + +module NexusSemanticLogger +end diff --git a/lib/nexus_semantic_logger/application.rb b/lib/nexus_semantic_logger/application.rb new file mode 100644 index 0000000..d810f2c --- /dev/null +++ b/lib/nexus_semantic_logger/application.rb @@ -0,0 +1,65 @@ +# frozen_string_literal: true +require 'semantic_logger' + +module NexusSemanticLogger + class Application + include SemanticLogger::Loggable + + def self.common(config) + # Set a safe logging level which individual environments can make more verbose if needed. + config.log_level = ENV.fetch('LOG_LEVEL', 'INFO') + + # semanticlogger ddtrace correlation. + # From https://github.com/DataDog/dd-trace-rb/issues/1450 + # Also https://docs.datadoghq.com/tracing/connect_logs_and_traces/ruby/ + config.log_tags = { + request_id: :request_id, + dd: -> (_) { + correlation = Datadog.tracer.active_correlation + { + trace_id: correlation.trace_id.to_s, + span_id: correlation.span_id.to_s, + env: correlation.env.to_s, + service: correlation.service.to_s, + version: correlation.version.to_s + } + }, + ddsource: ["ruby"] + } + + # Synchronous mode is vital when puma is in single thread mode. Must add appender AFTER setting sync. + SemanticLogger.sync! + + # Default logging is stdout in datadog compatible JSON. + config.rails_semantic_logger.format = NexusSemanticLogger::DatadogFormatter.new('users') + config.rails_semantic_logger.add_file_appender = false + config.semantic_logger.add_appender(io: $stdout, formatter: config.rails_semantic_logger.format) + + logger.info('SemanticLogger initialised.', level: config.log_level) + end + + def self.development(config) + # Enable debug globally. + config.log_level = ENV.fetch('LOG_LEVEL', 'DEBUG') + + # Change default logging to coloured logging on stdout. + config.semantic_logger.clear_appenders! + config.semantic_logger.add_appender(io: $stdout, formatter: :color) + 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) + end + + logger.info('SemanticLogger initialised in development.', level: config.log_level) + end + + 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) + end + end +end diff --git a/lib/nexus_semantic_logger/datadog_formatter.rb b/lib/nexus_semantic_logger/datadog_formatter.rb new file mode 100644 index 0000000..6c28a5c --- /dev/null +++ b/lib/nexus_semantic_logger/datadog_formatter.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true +require 'semantic_logger' + +module NexusSemanticLogger + # Some attributes are reserved for use by Datadog. + # https://docs.datadoghq.com/logs/log_configuration/attributes_naming_convention/#reserved-attributes + # host Supported by super. + # source Overridden by this class. + # status Supported by super as level, this class moves to status. + # date Supported by super as time, this class configures as date. + # message Supported by super. + # env Added by this class. + # service Added by this class. + class DatadogFormatter < SemanticLogger::Formatters::Raw + def initialize(service) + super(time_format: :iso_8601, time_key: :date) + @service = service + end + + def call(log, logger) + hash = super(log, logger).clone + hash[:source] = :rails + level = hash.delete(:level) + hash[:status] = level + hash[:env] = Rails.env + hash[:service] = @service + hash.delete(:application) + hash.delete(:environment) + hash.delete('') + # ddtrace correlation inserted via log_tags, but datadog expects them in the root hash. + named_tags = hash.delete(:named_tags) + if named_tags.is_a?(Hash) + hash.deep_merge!(named_tags) + end + hash.to_json + end + end +end diff --git a/nexus_semantic_logger.gemspec b/nexus_semantic_logger.gemspec index dc5832c..43f50f4 100644 --- a/nexus_semantic_logger.gemspec +++ b/nexus_semantic_logger.gemspec @@ -1,13 +1,16 @@ Gem::Specification.new do |spec| - spec.name = "nexus_semantic_logger" - spec.version = "1.0.0" - spec.summary = "semantic_logger usage for nexus" - spec.authors = ["Johnathon Harris"] - spec.email = "john.harris@nexusmods.com" + spec.name = "nexus_semantic_logger" + spec.version = "1.0.0" + spec.summary = "semantic_logger usage for nexus" + spec.authors = ["Johnathon Harris"] + spec.email = "john.harris@nexusmods.com" # Specify which files should be added to the gem when it is released. # The `git ls-files -z` loads the files in the RubyGem that have been added into git. spec.files = Dir.chdir(File.expand_path(__dir__)) do %x(git ls-files -z).split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) } end + spec.require_paths = ['lib'] + spec.add_dependency('amazing_print') + spec.add_dependency('rails_semantic_logger') + spec.add_dependency('net_tcp_client') # For TCP logging. end - -- GitLab