makit 0.0.98 → 0.0.111
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +41 -0
- data/exe/makit +5 -0
- data/lib/makit/apache.rb +7 -11
- data/lib/makit/cli/build_commands.rb +500 -0
- data/lib/makit/cli/generators/base_generator.rb +74 -0
- data/lib/makit/cli/generators/dotnet_generator.rb +50 -0
- data/lib/makit/cli/generators/generator_factory.rb +49 -0
- data/lib/makit/cli/generators/node_generator.rb +50 -0
- data/lib/makit/cli/generators/ruby_generator.rb +77 -0
- data/lib/makit/cli/generators/rust_generator.rb +50 -0
- data/lib/makit/cli/generators/templates/dotnet_templates.rb +167 -0
- data/lib/makit/cli/generators/templates/node_templates.rb +161 -0
- data/lib/makit/cli/generators/templates/ruby/gemfile.rb +26 -0
- data/lib/makit/cli/generators/templates/ruby/gemspec.rb +40 -0
- data/lib/makit/cli/generators/templates/ruby/main_lib.rb +33 -0
- data/lib/makit/cli/generators/templates/ruby/rakefile.rb +35 -0
- data/lib/makit/cli/generators/templates/ruby/readme.rb +63 -0
- data/lib/makit/cli/generators/templates/ruby/test.rb +39 -0
- data/lib/makit/cli/generators/templates/ruby/test_helper.rb +29 -0
- data/lib/makit/cli/generators/templates/ruby/version.rb +29 -0
- data/lib/makit/cli/generators/templates/rust_templates.rb +128 -0
- data/lib/makit/cli/main.rb +48 -19
- data/lib/makit/cli/project_commands.rb +868 -0
- data/lib/makit/cli/repository_commands.rb +661 -0
- data/lib/makit/cli/utility_commands.rb +521 -0
- data/lib/makit/command_runner.rb +187 -128
- data/lib/makit/commands/compatibility.rb +365 -0
- data/lib/makit/commands/factory.rb +359 -0
- data/lib/makit/commands/middleware/base.rb +73 -0
- data/lib/makit/commands/middleware/cache.rb +248 -0
- data/lib/makit/commands/middleware/command_logger.rb +323 -0
- data/lib/makit/commands/middleware/unified_logger.rb +243 -0
- data/lib/makit/commands/middleware/validator.rb +269 -0
- data/lib/makit/commands/request.rb +254 -0
- data/lib/makit/commands/result.rb +323 -0
- data/lib/makit/commands/runner.rb +317 -0
- data/lib/makit/commands/strategies/base.rb +160 -0
- data/lib/makit/commands/strategies/synchronous.rb +134 -0
- data/lib/makit/commands.rb +24 -3
- data/lib/makit/configuration/gitlab_helper.rb +60 -0
- data/lib/makit/configuration/project.rb +127 -0
- data/lib/makit/configuration/rakefile_helper.rb +43 -0
- data/lib/makit/configuration/step.rb +34 -0
- data/lib/makit/configuration.rb +14 -0
- data/lib/makit/content/default_gitignore.rb +4 -2
- data/lib/makit/content/default_rakefile.rb +4 -2
- data/lib/makit/content/gem_rakefile.rb +4 -2
- data/lib/makit/context.rb +1 -0
- data/lib/makit/data.rb +9 -10
- data/lib/makit/directories.rb +48 -52
- data/lib/makit/directory.rb +38 -52
- data/lib/makit/docs/files.rb +5 -10
- data/lib/makit/docs/rake.rb +16 -20
- data/lib/makit/dotnet/cli.rb +65 -0
- data/lib/makit/dotnet/project.rb +153 -0
- data/lib/makit/dotnet/solution.rb +38 -0
- data/lib/makit/dotnet/solution_classlib.rb +239 -0
- data/lib/makit/dotnet/solution_console.rb +264 -0
- data/lib/makit/dotnet/solution_maui.rb +354 -0
- data/lib/makit/dotnet/solution_wasm.rb +275 -0
- data/lib/makit/dotnet/solution_wpf.rb +304 -0
- data/lib/makit/dotnet.rb +54 -171
- data/lib/makit/email.rb +46 -17
- data/lib/makit/environment.rb +22 -19
- data/lib/makit/examples/runner.rb +370 -0
- data/lib/makit/exceptions.rb +45 -0
- data/lib/makit/fileinfo.rb +3 -5
- data/lib/makit/files.rb +12 -16
- data/lib/makit/gems.rb +40 -39
- data/lib/makit/git/cli.rb +54 -0
- data/lib/makit/git/repository.rb +90 -0
- data/lib/makit/git.rb +44 -91
- data/lib/makit/gitlab_runner.rb +0 -1
- data/lib/makit/humanize.rb +31 -23
- data/lib/makit/indexer.rb +15 -24
- data/lib/makit/logging/configuration.rb +305 -0
- data/lib/makit/logging/format_registry.rb +84 -0
- data/lib/makit/logging/formatters/base.rb +39 -0
- data/lib/makit/logging/formatters/console_formatter.rb +127 -0
- data/lib/makit/logging/formatters/json_formatter.rb +65 -0
- data/lib/makit/logging/formatters/plain_text_formatter.rb +71 -0
- data/lib/makit/logging/formatters/text_formatter.rb +64 -0
- data/lib/makit/logging/log_request.rb +115 -0
- data/lib/makit/logging/logger.rb +159 -0
- data/lib/makit/logging/sinks/base.rb +91 -0
- data/lib/makit/logging/sinks/console.rb +72 -0
- data/lib/makit/logging/sinks/file_sink.rb +92 -0
- data/lib/makit/logging/sinks/structured.rb +129 -0
- data/lib/makit/logging/sinks/unified_file_sink.rb +303 -0
- data/lib/makit/logging.rb +452 -37
- data/lib/makit/markdown.rb +18 -18
- data/lib/makit/mp/basic_object_mp.rb +5 -4
- data/lib/makit/mp/command_mp.rb +5 -5
- data/lib/makit/mp/command_request.mp.rb +3 -2
- data/lib/makit/mp/project_mp.rb +85 -96
- data/lib/makit/mp/string_mp.rb +245 -73
- data/lib/makit/nuget.rb +27 -25
- data/lib/makit/port.rb +25 -27
- data/lib/makit/process.rb +127 -29
- data/lib/makit/protoc.rb +27 -24
- data/lib/makit/rake/cli.rb +196 -0
- data/lib/makit/rake.rb +6 -6
- data/lib/makit/ruby/cli.rb +185 -0
- data/lib/makit/ruby.rb +25 -0
- data/lib/makit/secrets.rb +18 -18
- data/lib/makit/serializer.rb +29 -27
- data/lib/makit/services/builder.rb +186 -0
- data/lib/makit/services/error_handler.rb +226 -0
- data/lib/makit/services/repository_manager.rb +229 -0
- data/lib/makit/services/validator.rb +112 -0
- data/lib/makit/setup/classlib.rb +53 -0
- data/lib/makit/setup/gem.rb +250 -0
- data/lib/makit/setup/runner.rb +40 -0
- data/lib/makit/show.rb +16 -16
- data/lib/makit/storage.rb +32 -37
- data/lib/makit/symbols.rb +12 -0
- data/lib/makit/task_hooks.rb +125 -0
- data/lib/makit/task_info.rb +63 -21
- data/lib/makit/tasks/at_exit.rb +13 -0
- data/lib/makit/tasks/build.rb +18 -0
- data/lib/makit/tasks/clean.rb +11 -0
- data/lib/makit/tasks/hook_manager.rb +239 -0
- data/lib/makit/tasks/init.rb +47 -0
- data/lib/makit/tasks/integrate.rb +15 -0
- data/lib/makit/tasks/pull_incoming.rb +12 -0
- data/lib/makit/tasks/setup.rb +6 -0
- data/lib/makit/tasks/sync.rb +11 -0
- data/lib/makit/tasks/task_monkey_patch.rb +79 -0
- data/lib/makit/tasks.rb +5 -150
- data/lib/makit/test_cache.rb +239 -0
- data/lib/makit/v1/makit.v1_pb.rb +34 -35
- data/lib/makit/v1/makit.v1_services_pb.rb +2 -0
- data/lib/makit/version.rb +1 -60
- data/lib/makit/wix.rb +23 -23
- data/lib/makit/yaml.rb +18 -6
- data/lib/makit.rb +2 -261
- metadata +109 -145
- data/lib/makit/cli/clean.rb +0 -14
- data/lib/makit/cli/clone.rb +0 -59
- data/lib/makit/cli/init.rb +0 -38
- data/lib/makit/cli/make.rb +0 -54
- data/lib/makit/cli/new.rb +0 -37
- data/lib/makit/cli/nuget_cache.rb +0 -38
- data/lib/makit/cli/pull.rb +0 -31
- data/lib/makit/cli/setup.rb +0 -71
- data/lib/makit/cli/work.rb +0 -21
- data/lib/makit/content/default_gitignore.txt +0 -222
@@ -0,0 +1,129 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base"
|
4
|
+
|
5
|
+
module Makit
|
6
|
+
module Logging
|
7
|
+
module Sinks
|
8
|
+
# Structured sink for adding metadata to log requests
|
9
|
+
#
|
10
|
+
# This sink enriches log requests with structured metadata like
|
11
|
+
# process information, thread details, and other contextual data that
|
12
|
+
# can be useful for debugging and monitoring. It follows the same
|
13
|
+
# pattern as other sinks but focuses on data enrichment rather than output.
|
14
|
+
#
|
15
|
+
# @example Basic usage
|
16
|
+
# structured_sink = Structured.new
|
17
|
+
# logger = Logger.new(sinks: [structured_sink])
|
18
|
+
# logger.info("Processing started")
|
19
|
+
# # Adds metadata like process_id, thread_id, etc.
|
20
|
+
#
|
21
|
+
# @example With custom metadata
|
22
|
+
# structured_sink = Structured.new(
|
23
|
+
# custom_metadata: { environment: "production" }
|
24
|
+
# )
|
25
|
+
class Structured < Base
|
26
|
+
# Initialize structured sink
|
27
|
+
#
|
28
|
+
# @param include_process_info [Boolean] whether to include process information
|
29
|
+
# @param include_thread_info [Boolean] whether to include thread information
|
30
|
+
# @param include_timing [Boolean] whether to include timing information
|
31
|
+
# @param custom_metadata [Hash] custom metadata to add to all log requests
|
32
|
+
def initialize(include_process_info: true, include_thread_info: true, include_timing: true, custom_metadata: {})
|
33
|
+
@include_process_info = include_process_info
|
34
|
+
@include_thread_info = include_thread_info
|
35
|
+
@include_timing = include_timing
|
36
|
+
@custom_metadata = custom_metadata.dup
|
37
|
+
end
|
38
|
+
|
39
|
+
# Execute sink logic to add structured metadata
|
40
|
+
#
|
41
|
+
# @param log_request [LogRequest] the log request to process
|
42
|
+
# @yield [LogRequest] yields the processed log request to the next sink
|
43
|
+
# @yieldreturn [LogRequest] the processed log request
|
44
|
+
# @return [LogRequest] the final processed log request
|
45
|
+
def call(log_request, &block)
|
46
|
+
add_structured_metadata(log_request)
|
47
|
+
block&.call(log_request) if block_given?
|
48
|
+
log_request
|
49
|
+
end
|
50
|
+
|
51
|
+
# Get sink configuration
|
52
|
+
#
|
53
|
+
# @return [Hash] sink configuration
|
54
|
+
def config
|
55
|
+
{
|
56
|
+
name: self.class.name.split("::").last,
|
57
|
+
include_process_info: @include_process_info,
|
58
|
+
include_thread_info: @include_thread_info,
|
59
|
+
include_timing: @include_timing,
|
60
|
+
custom_metadata: @custom_metadata,
|
61
|
+
}
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
# Add structured metadata to the log request
|
67
|
+
#
|
68
|
+
# @param log_request [LogRequest] the log request to enrich
|
69
|
+
def add_structured_metadata(log_request)
|
70
|
+
metadata = {}
|
71
|
+
|
72
|
+
# Add process information
|
73
|
+
if @include_process_info
|
74
|
+
metadata.merge!(get_process_metadata)
|
75
|
+
end
|
76
|
+
|
77
|
+
# Add thread information
|
78
|
+
if @include_thread_info
|
79
|
+
metadata.merge!(get_thread_metadata)
|
80
|
+
end
|
81
|
+
|
82
|
+
# Add timing information
|
83
|
+
if @include_timing
|
84
|
+
metadata.merge!(get_timing_metadata)
|
85
|
+
end
|
86
|
+
|
87
|
+
# Add custom metadata
|
88
|
+
metadata.merge!(@custom_metadata)
|
89
|
+
|
90
|
+
# Add to log request
|
91
|
+
log_request.add_metadata(metadata)
|
92
|
+
end
|
93
|
+
|
94
|
+
# Get process-related metadata
|
95
|
+
#
|
96
|
+
# @return [Hash] process metadata
|
97
|
+
def get_process_metadata
|
98
|
+
{
|
99
|
+
process_id: ::Process.pid,
|
100
|
+
process_title: $0,
|
101
|
+
ruby_version: RUBY_VERSION,
|
102
|
+
ruby_platform: RUBY_PLATFORM,
|
103
|
+
}
|
104
|
+
end
|
105
|
+
|
106
|
+
# Get thread-related metadata
|
107
|
+
#
|
108
|
+
# @return [Hash] thread metadata
|
109
|
+
def get_thread_metadata
|
110
|
+
{
|
111
|
+
thread_id: Thread.current.object_id,
|
112
|
+
thread_name: Thread.current.name || "main",
|
113
|
+
}
|
114
|
+
end
|
115
|
+
|
116
|
+
# Get timing-related metadata
|
117
|
+
#
|
118
|
+
# @return [Hash] timing metadata
|
119
|
+
def get_timing_metadata
|
120
|
+
{
|
121
|
+
timestamp: Time.now.iso8601,
|
122
|
+
unix_timestamp: Time.now.to_i,
|
123
|
+
timezone: Time.now.zone,
|
124
|
+
}
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
@@ -0,0 +1,303 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base"
|
4
|
+
require_relative "../format_registry"
|
5
|
+
require "fileutils"
|
6
|
+
|
7
|
+
module Makit
|
8
|
+
module Logging
|
9
|
+
module Sinks
|
10
|
+
# Unified file sink with configurable multiple outputs
|
11
|
+
#
|
12
|
+
# This sink replaces the need for multiple separate sinks by providing
|
13
|
+
# a single, highly configurable sink that can write to multiple files
|
14
|
+
# with different formats, filtering, and options. It supports console
|
15
|
+
# output, file logging, and structured logging through configuration.
|
16
|
+
#
|
17
|
+
# @example Basic usage with console and file output
|
18
|
+
# sink = UnifiedFileSink.new(
|
19
|
+
# configurations: [
|
20
|
+
# { file: $stdout, format: :console },
|
21
|
+
# { file: "logs/app.log", format: :json }
|
22
|
+
# ]
|
23
|
+
# )
|
24
|
+
#
|
25
|
+
# @example Advanced configuration with filtering and formatting
|
26
|
+
# sink = UnifiedFileSink.new(
|
27
|
+
# configurations: [
|
28
|
+
# {
|
29
|
+
# file: $stdout,
|
30
|
+
# format: :console,
|
31
|
+
# show_timestamp: true,
|
32
|
+
# show_level: true
|
33
|
+
# },
|
34
|
+
# {
|
35
|
+
# file: "logs/debug.log",
|
36
|
+
# format: :text,
|
37
|
+
# min_level: :debug,
|
38
|
+
# include_context: true
|
39
|
+
# },
|
40
|
+
# {
|
41
|
+
# file: "logs/audit.log",
|
42
|
+
# format: :json,
|
43
|
+
# min_level: :info,
|
44
|
+
# include_metadata: true
|
45
|
+
# }
|
46
|
+
# ]
|
47
|
+
# )
|
48
|
+
class UnifiedFileSink < Base
|
49
|
+
# @return [Array<Hash>] list of output configurations
|
50
|
+
attr_reader :configurations
|
51
|
+
|
52
|
+
# Initialize unified file sink
|
53
|
+
#
|
54
|
+
# @param configurations [Array<Hash>] list of output configurations
|
55
|
+
def initialize(configurations: [])
|
56
|
+
@configurations = validate_configurations(configurations)
|
57
|
+
@formatters = {}
|
58
|
+
@files = {}
|
59
|
+
|
60
|
+
# Pre-initialize formatters and files
|
61
|
+
initialize_formatters
|
62
|
+
initialize_files
|
63
|
+
end
|
64
|
+
|
65
|
+
# Execute sink logic to write log entry to configured outputs
|
66
|
+
#
|
67
|
+
# @param log_request [LogRequest] the log request to process
|
68
|
+
# @yield [LogRequest] yields the processed log request to the next sink
|
69
|
+
# @yieldreturn [LogRequest] the processed log request
|
70
|
+
# @return [LogRequest] the final processed log request
|
71
|
+
def call(log_request, &block)
|
72
|
+
write_to_outputs(log_request)
|
73
|
+
block&.call(log_request) if block_given?
|
74
|
+
log_request
|
75
|
+
end
|
76
|
+
|
77
|
+
# Get sink configuration
|
78
|
+
#
|
79
|
+
# @return [Hash] sink configuration
|
80
|
+
def config
|
81
|
+
{
|
82
|
+
name: self.class.name.split("::").last,
|
83
|
+
configurations_count: @configurations.length,
|
84
|
+
configurations: @configurations.map { |config| sanitize_config(config) },
|
85
|
+
}
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
# Validate configuration array
|
91
|
+
#
|
92
|
+
# @param configurations [Array<Hash>] configurations to validate
|
93
|
+
# @return [Array<Hash>] validated configurations
|
94
|
+
# @raise [ArgumentError] if configuration is invalid
|
95
|
+
def validate_configurations(configurations)
|
96
|
+
raise ArgumentError, "configurations must be an array" unless configurations.is_a?(Array)
|
97
|
+
raise ArgumentError, "at least one configuration is required" if configurations.empty?
|
98
|
+
|
99
|
+
configurations.each_with_index do |config, index|
|
100
|
+
validate_single_configuration(config, index)
|
101
|
+
end
|
102
|
+
|
103
|
+
configurations
|
104
|
+
end
|
105
|
+
|
106
|
+
# Validate a single configuration
|
107
|
+
#
|
108
|
+
# @param config [Hash] configuration to validate
|
109
|
+
# @param index [Integer] configuration index for error messages
|
110
|
+
# @raise [ArgumentError] if configuration is invalid
|
111
|
+
def validate_single_configuration(config, index)
|
112
|
+
raise ArgumentError, "configuration #{index} must be a hash" unless config.is_a?(Hash)
|
113
|
+
|
114
|
+
required_keys = [:file, :format]
|
115
|
+
missing_keys = required_keys - config.keys
|
116
|
+
raise ArgumentError, "configuration #{index} missing required keys: #{missing_keys.join(", ")}" unless missing_keys.empty?
|
117
|
+
|
118
|
+
# Validate file
|
119
|
+
file = config[:file]
|
120
|
+
unless file.is_a?(String) || file.is_a?(IO) || file.respond_to?(:write)
|
121
|
+
raise ArgumentError, "configuration #{index} file must be a String path, IO object, or writable object"
|
122
|
+
end
|
123
|
+
|
124
|
+
# Validate format
|
125
|
+
format = config[:format]
|
126
|
+
unless format.is_a?(Symbol) || format.is_a?(String)
|
127
|
+
raise ArgumentError, "configuration #{index} format must be a Symbol or String"
|
128
|
+
end
|
129
|
+
|
130
|
+
# Validate log levels if specified
|
131
|
+
if config[:min_level] && !valid_log_level?(config[:min_level])
|
132
|
+
raise ArgumentError, "configuration #{index} min_level must be a valid log level"
|
133
|
+
end
|
134
|
+
|
135
|
+
if config[:max_level] && !valid_log_level?(config[:max_level])
|
136
|
+
raise ArgumentError, "configuration #{index} max_level must be a valid log level"
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
# Check if log level is valid
|
141
|
+
#
|
142
|
+
# @param level [Symbol] log level to check
|
143
|
+
# @return [Boolean] true if valid
|
144
|
+
def valid_log_level?(level)
|
145
|
+
%i[debug info warn error fatal success].include?(level)
|
146
|
+
end
|
147
|
+
|
148
|
+
# Initialize formatters for each configuration
|
149
|
+
#
|
150
|
+
# @return [void]
|
151
|
+
def initialize_formatters
|
152
|
+
@configurations.each_with_index do |config, index|
|
153
|
+
format = config[:format].to_sym
|
154
|
+
formatter_options = config[:formatter_options] || {}
|
155
|
+
|
156
|
+
# Merge configuration options into formatter options
|
157
|
+
formatter_options[:include_context] = config[:include_context] if config.key?(:include_context)
|
158
|
+
formatter_options[:include_metadata] = config[:include_metadata] if config.key?(:include_metadata)
|
159
|
+
formatter_options[:show_timestamp] = config[:show_timestamp] if config.key?(:show_timestamp)
|
160
|
+
formatter_options[:show_level] = config[:show_level] if config.key?(:show_level)
|
161
|
+
|
162
|
+
begin
|
163
|
+
formatter_class = FormatRegistry.get(format)
|
164
|
+
|
165
|
+
# Handle different formatter initialization patterns
|
166
|
+
if formatter_class == Formatters::ConsoleFormatter
|
167
|
+
# ConsoleFormatter expects keyword arguments
|
168
|
+
@formatters[index] = formatter_class.new(
|
169
|
+
show_timestamp: formatter_options[:show_timestamp] || false,
|
170
|
+
show_level: formatter_options[:show_level] || false,
|
171
|
+
)
|
172
|
+
elsif formatter_class == Formatters::TextFormatter
|
173
|
+
# TextFormatter expects keyword arguments
|
174
|
+
@formatters[index] = formatter_class.new(
|
175
|
+
timestamp_format: formatter_options[:timestamp_format] || "%Y-%m-%d %H:%M:%S",
|
176
|
+
include_context: formatter_options[:include_context] || false,
|
177
|
+
)
|
178
|
+
elsif formatter_class == Formatters::JsonFormatter
|
179
|
+
# JsonFormatter expects keyword arguments
|
180
|
+
@formatters[index] = formatter_class.new(
|
181
|
+
options: formatter_options,
|
182
|
+
)
|
183
|
+
elsif formatter_class == Formatters::PlainTextFormatter
|
184
|
+
# PlainTextFormatter expects keyword arguments
|
185
|
+
@formatters[index] = formatter_class.new(
|
186
|
+
include_context: formatter_options[:include_context] || false,
|
187
|
+
)
|
188
|
+
else
|
189
|
+
# Other formatters expect hash or no arguments
|
190
|
+
if formatter_options.empty?
|
191
|
+
@formatters[index] = formatter_class.new
|
192
|
+
else
|
193
|
+
@formatters[index] = formatter_class.new(formatter_options)
|
194
|
+
end
|
195
|
+
end
|
196
|
+
rescue ArgumentError => e
|
197
|
+
raise ArgumentError, "configuration #{index} has invalid format '#{format}': #{e.message}"
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
# Initialize file handles for each configuration
|
203
|
+
#
|
204
|
+
# @return [void]
|
205
|
+
def initialize_files
|
206
|
+
@configurations.each_with_index do |config, index|
|
207
|
+
file = config[:file]
|
208
|
+
|
209
|
+
if file.is_a?(String)
|
210
|
+
# Ensure directory exists
|
211
|
+
FileUtils.mkdir_p(File.dirname(file)) unless File.dirname(file) == "."
|
212
|
+
|
213
|
+
# Open file with appropriate mode
|
214
|
+
mode = config[:append] != false ? "a" : "w"
|
215
|
+
@files[index] = File.open(file, mode)
|
216
|
+
else
|
217
|
+
# Use IO object directly
|
218
|
+
@files[index] = file
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
# Write log request to all applicable outputs
|
224
|
+
#
|
225
|
+
# @param log_request [LogRequest] the log request to write
|
226
|
+
def write_to_outputs(log_request)
|
227
|
+
@configurations.each_with_index do |config, index|
|
228
|
+
next unless should_output?(log_request, config)
|
229
|
+
|
230
|
+
formatter = @formatters[index]
|
231
|
+
file = @files[index]
|
232
|
+
|
233
|
+
formatted_message = formatter.format(log_request)
|
234
|
+
file.write(formatted_message)
|
235
|
+
file.write("\n") unless config[:no_newline]
|
236
|
+
file.flush
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
# Check if log request should be output to this configuration
|
241
|
+
#
|
242
|
+
# @param log_request [LogRequest] the log request
|
243
|
+
# @param config [Hash] the output configuration
|
244
|
+
# @return [Boolean] true if should output
|
245
|
+
def should_output?(log_request, config)
|
246
|
+
# Check level filtering
|
247
|
+
if config[:min_level] && !level_greater_or_equal?(log_request.level, config[:min_level])
|
248
|
+
return false
|
249
|
+
end
|
250
|
+
|
251
|
+
if config[:max_level] && !level_less_or_equal?(log_request.level, config[:max_level])
|
252
|
+
return false
|
253
|
+
end
|
254
|
+
|
255
|
+
# Check custom condition
|
256
|
+
if config[:condition] && !config[:condition].call(log_request)
|
257
|
+
return false
|
258
|
+
end
|
259
|
+
|
260
|
+
true
|
261
|
+
end
|
262
|
+
|
263
|
+
# Check if log level is greater than or equal to minimum level
|
264
|
+
#
|
265
|
+
# @param level [Symbol] log level to check
|
266
|
+
# @param min_level [Symbol] minimum level
|
267
|
+
# @return [Boolean] true if level >= min_level
|
268
|
+
def level_greater_or_equal?(level, min_level)
|
269
|
+
levels = %i[debug info warn error fatal success]
|
270
|
+
levels.index(level) >= levels.index(min_level)
|
271
|
+
end
|
272
|
+
|
273
|
+
# Check if log level is less than or equal to maximum level
|
274
|
+
#
|
275
|
+
# @param level [Symbol] log level to check
|
276
|
+
# @param max_level [Symbol] maximum level
|
277
|
+
# @return [Boolean] true if level <= max_level
|
278
|
+
def level_less_or_equal?(level, max_level)
|
279
|
+
levels = %i[debug info warn error fatal success]
|
280
|
+
levels.index(level) <= levels.index(max_level)
|
281
|
+
end
|
282
|
+
|
283
|
+
# Sanitize configuration for display (remove sensitive data)
|
284
|
+
#
|
285
|
+
# @param config [Hash] configuration to sanitize
|
286
|
+
# @return [Hash] sanitized configuration
|
287
|
+
def sanitize_config(config)
|
288
|
+
sanitized = config.dup
|
289
|
+
|
290
|
+
# Remove condition procs and other non-serializable items
|
291
|
+
sanitized.delete(:condition)
|
292
|
+
|
293
|
+
# Convert IO objects to string representation
|
294
|
+
if sanitized[:file].is_a?(IO)
|
295
|
+
sanitized[:file] = "<#{sanitized[:file].class.name}>"
|
296
|
+
end
|
297
|
+
|
298
|
+
sanitized
|
299
|
+
end
|
300
|
+
end
|
301
|
+
end
|
302
|
+
end
|
303
|
+
end
|