makit 0.0.140 → 0.0.142
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 -41
- data/exe/makit +5 -5
- data/lib/makit/apache.rb +28 -28
- data/lib/makit/auto.rb +48 -48
- data/lib/makit/cli/build_commands.rb +500 -500
- data/lib/makit/cli/generators/base_generator.rb +74 -74
- data/lib/makit/cli/generators/dotnet_generator.rb +50 -50
- data/lib/makit/cli/generators/generator_factory.rb +49 -49
- data/lib/makit/cli/generators/node_generator.rb +50 -50
- data/lib/makit/cli/generators/ruby_generator.rb +77 -77
- data/lib/makit/cli/generators/rust_generator.rb +50 -50
- data/lib/makit/cli/generators/templates/dotnet_templates.rb +167 -167
- data/lib/makit/cli/generators/templates/node_templates.rb +161 -161
- data/lib/makit/cli/generators/templates/ruby/gemfile.rb +26 -26
- data/lib/makit/cli/generators/templates/ruby/gemspec.rb +40 -40
- data/lib/makit/cli/generators/templates/ruby/main_lib.rb +33 -33
- data/lib/makit/cli/generators/templates/ruby/rakefile.rb +35 -35
- data/lib/makit/cli/generators/templates/ruby/readme.rb +63 -63
- data/lib/makit/cli/generators/templates/ruby/test.rb +39 -39
- data/lib/makit/cli/generators/templates/ruby/test_helper.rb +29 -29
- data/lib/makit/cli/generators/templates/ruby/version.rb +29 -29
- data/lib/makit/cli/generators/templates/rust_templates.rb +128 -128
- data/lib/makit/cli/main.rb +69 -69
- data/lib/makit/cli/project_commands.rb +868 -868
- data/lib/makit/cli/repository_commands.rb +661 -661
- data/lib/makit/cli/strategy_commands.rb +203 -203
- data/lib/makit/cli/utility_commands.rb +521 -521
- data/lib/makit/commands/factory.rb +359 -359
- data/lib/makit/commands/middleware/base.rb +73 -73
- data/lib/makit/commands/middleware/cache.rb +248 -248
- data/lib/makit/commands/middleware/command_logger.rb +312 -312
- data/lib/makit/commands/middleware/validator.rb +269 -269
- data/lib/makit/commands/request.rb +316 -316
- data/lib/makit/commands/result.rb +323 -323
- data/lib/makit/commands/runner.rb +388 -385
- data/lib/makit/commands/strategies/base.rb +171 -171
- data/lib/makit/commands/strategies/child_process.rb +165 -165
- data/lib/makit/commands/strategies/factory.rb +136 -136
- data/lib/makit/commands/strategies/synchronous.rb +139 -139
- data/lib/makit/commands.rb +50 -50
- data/lib/makit/configuration/dotnet_project.rb +12 -12
- data/lib/makit/configuration/gitlab_helper.rb +58 -58
- data/lib/makit/configuration/project.rb +168 -168
- data/lib/makit/configuration/rakefile_helper.rb +43 -43
- data/lib/makit/configuration/step.rb +34 -34
- data/lib/makit/configuration/timeout.rb +74 -74
- data/lib/makit/configuration.rb +15 -15
- data/lib/makit/content/default_gitignore.rb +7 -7
- data/lib/makit/content/default_gitignore.txt +225 -225
- data/lib/makit/content/default_rakefile.rb +13 -13
- data/lib/makit/content/gem_rakefile.rb +16 -16
- data/lib/makit/context.rb +1 -1
- data/lib/makit/data.rb +49 -49
- data/lib/makit/directories.rb +140 -140
- data/lib/makit/directory.rb +262 -262
- data/lib/makit/docs/files.rb +89 -89
- data/lib/makit/docs/rake.rb +102 -102
- data/lib/makit/dotnet/cli.rb +69 -69
- data/lib/makit/dotnet/project.rb +217 -217
- data/lib/makit/dotnet/solution.rb +38 -38
- data/lib/makit/dotnet/solution_classlib.rb +239 -239
- data/lib/makit/dotnet/solution_console.rb +264 -264
- data/lib/makit/dotnet/solution_maui.rb +354 -354
- data/lib/makit/dotnet/solution_wasm.rb +275 -275
- data/lib/makit/dotnet/solution_wpf.rb +304 -304
- data/lib/makit/dotnet.rb +102 -102
- data/lib/makit/email.rb +90 -90
- data/lib/makit/environment.rb +142 -142
- data/lib/makit/examples/runner.rb +370 -370
- data/lib/makit/exceptions.rb +45 -45
- data/lib/makit/fileinfo.rb +24 -24
- data/lib/makit/files.rb +43 -43
- data/lib/makit/gems.rb +40 -40
- data/lib/makit/git/cli.rb +54 -54
- data/lib/makit/git/repository.rb +90 -90
- data/lib/makit/git.rb +98 -98
- data/lib/makit/gitlab_runner.rb +59 -59
- data/lib/makit/humanize.rb +137 -137
- data/lib/makit/indexer.rb +47 -47
- data/lib/makit/logging/configuration.rb +308 -308
- data/lib/makit/logging/format_registry.rb +84 -84
- data/lib/makit/logging/formatters/base.rb +39 -39
- data/lib/makit/logging/formatters/console_formatter.rb +140 -140
- data/lib/makit/logging/formatters/json_formatter.rb +65 -65
- data/lib/makit/logging/formatters/plain_text_formatter.rb +71 -71
- data/lib/makit/logging/formatters/text_formatter.rb +64 -64
- data/lib/makit/logging/log_request.rb +119 -119
- data/lib/makit/logging/logger.rb +199 -199
- data/lib/makit/logging/sinks/base.rb +91 -91
- data/lib/makit/logging/sinks/console.rb +72 -72
- data/lib/makit/logging/sinks/file_sink.rb +92 -92
- data/lib/makit/logging/sinks/structured.rb +123 -123
- data/lib/makit/logging/sinks/unified_file_sink.rb +296 -296
- data/lib/makit/logging.rb +565 -565
- data/lib/makit/markdown.rb +75 -75
- data/lib/makit/mp/basic_object_mp.rb +17 -17
- data/lib/makit/mp/command_mp.rb +13 -13
- data/lib/makit/mp/command_request.mp.rb +17 -17
- data/lib/makit/mp/project_mp.rb +199 -199
- data/lib/makit/mp/string_mp.rb +199 -191
- data/lib/makit/nuget.rb +74 -74
- data/lib/makit/port.rb +32 -32
- data/lib/makit/process.rb +163 -163
- data/lib/makit/protoc.rb +107 -107
- data/lib/makit/rake/cli.rb +196 -196
- data/lib/makit/rake/trace_controller.rb +173 -173
- data/lib/makit/rake.rb +80 -80
- data/lib/makit/ruby/cli.rb +185 -185
- data/lib/makit/ruby.rb +25 -25
- data/lib/makit/secrets.rb +51 -51
- data/lib/makit/serializer.rb +130 -130
- data/lib/makit/services/builder.rb +186 -186
- data/lib/makit/services/error_handler.rb +226 -226
- data/lib/makit/services/repository_manager.rb +231 -231
- data/lib/makit/services/validator.rb +112 -112
- data/lib/makit/setup/classlib.rb +101 -101
- data/lib/makit/setup/gem.rb +268 -268
- data/lib/makit/setup/razorclasslib.rb +101 -101
- data/lib/makit/setup/runner.rb +54 -54
- data/lib/makit/setup.rb +5 -5
- data/lib/makit/show.rb +110 -110
- data/lib/makit/storage.rb +126 -126
- data/lib/makit/symbols.rb +170 -170
- data/lib/makit/task_info.rb +130 -130
- data/lib/makit/tasks/at_exit.rb +15 -15
- data/lib/makit/tasks/build.rb +22 -22
- data/lib/makit/tasks/clean.rb +13 -13
- data/lib/makit/tasks/configure.rb +10 -10
- data/lib/makit/tasks/format.rb +10 -10
- data/lib/makit/tasks/hook_manager.rb +443 -443
- data/lib/makit/tasks/init.rb +49 -49
- data/lib/makit/tasks/integrate.rb +29 -29
- data/lib/makit/tasks/pull_incoming.rb +13 -13
- data/lib/makit/tasks/setup.rb +13 -13
- data/lib/makit/tasks/sync.rb +17 -17
- data/lib/makit/tasks/tag.rb +16 -16
- data/lib/makit/tasks/task_monkey_patch.rb +81 -81
- data/lib/makit/tasks/test.rb +22 -22
- data/lib/makit/tasks/update.rb +18 -18
- data/lib/makit/tasks.rb +20 -20
- data/lib/makit/test_cache.rb +239 -239
- data/lib/makit/tree.rb +37 -37
- data/lib/makit/v1/makit.v1_pb.rb +35 -35
- data/lib/makit/v1/makit.v1_services_pb.rb +27 -27
- data/lib/makit/version.rb +99 -99
- data/lib/makit/version_util.rb +21 -21
- data/lib/makit/wix.rb +95 -95
- data/lib/makit/yaml.rb +29 -29
- data/lib/makit/zip.rb +17 -17
- data/lib/makit copy.rb +44 -44
- data/lib/makit.rb +43 -42
- metadata +2 -2
data/lib/makit/logging.rb
CHANGED
@@ -1,565 +1,565 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "logger"
|
4
|
-
begin
|
5
|
-
require "colorize"
|
6
|
-
rescue LoadError
|
7
|
-
# colorize gem not available, define a no-op colorize method
|
8
|
-
class String
|
9
|
-
def colorize(*_args)
|
10
|
-
self
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
14
|
-
require_relative "symbols"
|
15
|
-
require_relative "logging/logger"
|
16
|
-
require_relative "logging/log_request"
|
17
|
-
require_relative "logging/sinks/base"
|
18
|
-
require_relative "logging/sinks/console"
|
19
|
-
require_relative "logging/sinks/file_sink"
|
20
|
-
require_relative "logging/sinks/structured"
|
21
|
-
require_relative "logging/sinks/unified_file_sink"
|
22
|
-
require_relative "logging/configuration"
|
23
|
-
|
24
|
-
# This module provides classes for the Makit gem.
|
25
|
-
module Makit
|
26
|
-
# Logging infrastructure for the Makit gem
|
27
|
-
#
|
28
|
-
# This module provides a comprehensive logging system with multiple formatters,
|
29
|
-
# multi-target output capabilities, and configurable log levels. It supports:
|
30
|
-
#
|
31
|
-
# - Plain text logging (suitable for files)
|
32
|
-
# - Colored console output (improved terminal readability)
|
33
|
-
# - Structured JSON logging (machine-parsable format)
|
34
|
-
# - Multi-target logging (write to multiple destinations simultaneously)
|
35
|
-
# - Sink-based output processing (similar to Commands::Runner)
|
36
|
-
#
|
37
|
-
# @deprecated The legacy MultiLogger, Formatter classes, and create_logger method
|
38
|
-
# are deprecated and will be removed in version 0.2.0. Use the new Logger class
|
39
|
-
# with sinks instead.
|
40
|
-
#
|
41
|
-
# @example Basic usage with new architecture (recommended)
|
42
|
-
# Makit::Logging.info("Application started")
|
43
|
-
# Makit::Logging.success("Build completed")
|
44
|
-
# Makit::Logging.error("Something went wrong")
|
45
|
-
#
|
46
|
-
# @example Custom logger configuration
|
47
|
-
# logger = Makit::Logging::Logger.new(
|
48
|
-
# sinks: [
|
49
|
-
# Makit::Logging::Sinks::Console.new,
|
50
|
-
# Makit::Logging::Sinks::FileSink.new(log_file: "custom.log")
|
51
|
-
# ]
|
52
|
-
# )
|
53
|
-
# logger.info("Custom message")
|
54
|
-
#
|
55
|
-
# @example Legacy usage (deprecated - will be removed in v0.2.0)
|
56
|
-
# logger = Makit::Logging::MultiLogger.create_logger
|
57
|
-
# logger.info("Application started")
|
58
|
-
# logger.error("Something went wrong")
|
59
|
-
module Logging
|
60
|
-
ANSI_COLOR_REGEX = /\e\[[0-9;]*m/
|
61
|
-
|
62
|
-
# Log levels that can be configured
|
63
|
-
LOG_LEVELS = {
|
64
|
-
debug: ::Logger::DEBUG,
|
65
|
-
info: ::Logger::INFO,
|
66
|
-
warn: ::Logger::WARN,
|
67
|
-
error: ::Logger::ERROR,
|
68
|
-
fatal: ::Logger::FATAL,
|
69
|
-
}.freeze
|
70
|
-
|
71
|
-
# Default log level
|
72
|
-
DEFAULT_LOG_LEVEL = :info
|
73
|
-
|
74
|
-
# Get the current log level from environment or use default
|
75
|
-
def self.current_log_level
|
76
|
-
env_level = ENV["LOG_LEVEL"]&.downcase&.to_sym
|
77
|
-
return env_level if env_level && LOG_LEVELS.key?(env_level)
|
78
|
-
|
79
|
-
DEFAULT_LOG_LEVEL
|
80
|
-
end
|
81
|
-
|
82
|
-
# Get the current verbosity level from environment or use default
|
83
|
-
def self.current_verbosity
|
84
|
-
env_verbosity = ENV["VERBOSITY"]&.downcase&.to_sym
|
85
|
-
return env_verbosity if env_verbosity && %i[quiet normal verbose debug].include?(env_verbosity)
|
86
|
-
|
87
|
-
:normal
|
88
|
-
end
|
89
|
-
|
90
|
-
# Get the current verbosity level from the default logger
|
91
|
-
#
|
92
|
-
# @return [Symbol] current verbosity level (:quiet, :normal, :verbose, :debug)
|
93
|
-
def self.verbosity
|
94
|
-
DEFAULT_LOGGER.verbosity
|
95
|
-
end
|
96
|
-
|
97
|
-
# Logs the duration of a rake task to a file
|
98
|
-
#
|
99
|
-
# This method calculates the elapsed time since the STARTTIME constant was set
|
100
|
-
# and appends this information to a log file. Used to track performance of rake tasks.
|
101
|
-
#
|
102
|
-
# @return [nil]
|
103
|
-
def self.log_rake_duration
|
104
|
-
# use the STARTTIME constant to log the duration of the rake task
|
105
|
-
# to the log/rake.duration.txt file
|
106
|
-
duration = Time.now - STARTTIME
|
107
|
-
FileUtils.mkdir_p("log")
|
108
|
-
File.open("log/rake.duration.txt", "a") do |file|
|
109
|
-
file.puts "Rake task duration: #{duration} seconds"
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
# Plain text log formatter that strips ANSI color codes
|
114
|
-
#
|
115
|
-
# This formatter removes color codes from log messages and provides
|
116
|
-
# clean, plain text output suitable for file logging or systems
|
117
|
-
# that don't support color output.
|
118
|
-
#
|
119
|
-
# @deprecated This class is deprecated and will be removed in version 0.2.0.
|
120
|
-
# Use Makit::Logging::Logger with Makit::Logging::Sinks::FileSink instead.
|
121
|
-
class PlainFormatter < ::Logger::Formatter
|
122
|
-
# Format a log message as plain text
|
123
|
-
#
|
124
|
-
# @param severity [String] log level (DEBUG, INFO, WARN, ERROR, FATAL)
|
125
|
-
# @param time [Time] timestamp of the log message
|
126
|
-
# @param _progname [String] program name (unused)
|
127
|
-
# @param msg [String] the log message content
|
128
|
-
# @return [String] formatted plain text log entry
|
129
|
-
def call(severity, time, _progname, msg)
|
130
|
-
warn "Makit::Logging::PlainFormatter is deprecated and will be removed in version 0.2.0. Use Makit::Logging::Logger with Makit::Logging::Sinks::FileSink instead."
|
131
|
-
stripped_msg = msg.gsub(ANSI_COLOR_REGEX, "") # Remove ANSI color codes
|
132
|
-
timestamp = time.strftime("%Y-%m-%d %H:%M:%S")
|
133
|
-
"[#{timestamp}] #{severity}: #{stripped_msg}\n"
|
134
|
-
end
|
135
|
-
end
|
136
|
-
|
137
|
-
# Colored log formatter for terminal output
|
138
|
-
#
|
139
|
-
# This formatter adds appropriate colors to different log levels
|
140
|
-
# to improve readability in terminal environments. Colors are:
|
141
|
-
# DEBUG (light blue), INFO (green), WARN (yellow), ERROR (red), FATAL (bold red)
|
142
|
-
#
|
143
|
-
# @deprecated This class is deprecated and will be removed in version 0.2.0.
|
144
|
-
# Use Makit::Logging::Logger with Makit::Logging::Sinks::Console instead.
|
145
|
-
class ColorFormatter < ::Logger::Formatter
|
146
|
-
# Format a log message with colors
|
147
|
-
#
|
148
|
-
# @param severity [String] log level (DEBUG, INFO, WARN, ERROR, FATAL)
|
149
|
-
# @param time [Time] timestamp of the log message
|
150
|
-
# @param _progname [String] program name (unused)
|
151
|
-
# @param msg [String] the log message content
|
152
|
-
# @return [String] formatted colored log entry
|
153
|
-
def call(severity, time, _progname, msg)
|
154
|
-
warn "Makit::Logging::ColorFormatter is deprecated and will be removed in version 0.2.0. Use Makit::Logging::Logger with Makit::Logging::Sinks::Console instead."
|
155
|
-
timestamp = time.strftime("%Y-%m-%d %H:%M:%S")
|
156
|
-
colored_severity = colorize_severity(severity)
|
157
|
-
"[#{timestamp}] #{colored_severity}: #{msg}\n"
|
158
|
-
end
|
159
|
-
|
160
|
-
private
|
161
|
-
|
162
|
-
def colorize_severity(severity)
|
163
|
-
case severity
|
164
|
-
when "DEBUG"
|
165
|
-
severity.light_blue
|
166
|
-
when "INFO"
|
167
|
-
severity.green
|
168
|
-
when "WARN"
|
169
|
-
severity.yellow
|
170
|
-
when "ERROR"
|
171
|
-
severity.red
|
172
|
-
when "FATAL"
|
173
|
-
severity.red.bold
|
174
|
-
else
|
175
|
-
severity
|
176
|
-
end
|
177
|
-
end
|
178
|
-
end
|
179
|
-
|
180
|
-
# Structured JSON log formatter
|
181
|
-
#
|
182
|
-
# This formatter outputs log messages as JSON objects with structured
|
183
|
-
# fields including timestamp, level, message, and program name.
|
184
|
-
# Useful for log aggregation systems and machine parsing.
|
185
|
-
#
|
186
|
-
# @deprecated This class is deprecated and will be removed in version 0.2.0.
|
187
|
-
# Use Makit::Logging::Logger with Makit::Logging::Sinks::FileSink (formatter: :json) instead.
|
188
|
-
class StructuredFormatter < ::Logger::Formatter
|
189
|
-
# Format a log message as JSON
|
190
|
-
#
|
191
|
-
# @param severity [String] log level (DEBUG, INFO, WARN, ERROR, FATAL)
|
192
|
-
# @param time [Time] timestamp of the log message
|
193
|
-
# @param progname [String] program name
|
194
|
-
# @param msg [String] the log message content
|
195
|
-
# @return [String] JSON formatted log entry with newline
|
196
|
-
def call(severity, time, progname, msg)
|
197
|
-
warn "Makit::Logging::StructuredFormatter is deprecated and will be removed in version 0.2.0. Use Makit::Logging::Logger with Makit::Logging::Sinks::FileSink (formatter: :json) instead."
|
198
|
-
timestamp = time.strftime("%Y-%m-%d %H:%M:%S.%L")
|
199
|
-
{
|
200
|
-
timestamp: timestamp,
|
201
|
-
level: severity,
|
202
|
-
message: msg,
|
203
|
-
progname: progname,
|
204
|
-
}.to_json + "\n"
|
205
|
-
end
|
206
|
-
end
|
207
|
-
|
208
|
-
# Multi-target logger that writes to multiple destinations
|
209
|
-
#
|
210
|
-
# This logger allows writing log messages to multiple targets simultaneously,
|
211
|
-
# such as both stdout and a file, or multiple files with different formats.
|
212
|
-
#
|
213
|
-
# @deprecated This class is deprecated and will be removed in version 0.2.0.
|
214
|
-
# Use Makit::Logging::Logger with multiple middleware instead.
|
215
|
-
#
|
216
|
-
# @example Create a logger that writes to both console and file
|
217
|
-
# stdout_logger = Logger.new($stdout)
|
218
|
-
# file_logger = Logger.new("app.log")
|
219
|
-
# multi_logger = MultiLogger.new(stdout_logger, file_logger)
|
220
|
-
# multi_logger.info("This goes to both destinations")
|
221
|
-
class MultiLogger
|
222
|
-
# Initialize a new MultiLogger with multiple logging targets
|
223
|
-
#
|
224
|
-
# @param targets [Array<Logger>] One or more logger instances to write to
|
225
|
-
def initialize(*targets)
|
226
|
-
warn "Makit::Logging::MultiLogger is deprecated and will be removed in version 0.2.0. Use Makit::Logging::Logger with middleware instead."
|
227
|
-
@targets = targets
|
228
|
-
end
|
229
|
-
|
230
|
-
# Add a message to all logger targets
|
231
|
-
#
|
232
|
-
# @param severity [Integer] The severity level (::Logger::DEBUG, ::Logger::INFO, etc.)
|
233
|
-
# @param message [String, nil] The message to log (or nil if using block)
|
234
|
-
# @param progname [String, nil] The program name to include in the log
|
235
|
-
# @param block [Proc, nil] Optional block that returns the message to log
|
236
|
-
# @return [nil]
|
237
|
-
def add(severity, message = nil, progname = nil, &block)
|
238
|
-
@targets.each do |logger|
|
239
|
-
logger.add(severity, message, progname, &block)
|
240
|
-
logger.flush if logger.respond_to?(:flush)
|
241
|
-
end
|
242
|
-
end
|
243
|
-
|
244
|
-
# Append a message directly to all logger targets
|
245
|
-
#
|
246
|
-
# @param message [String] The message to append to all loggers
|
247
|
-
# @return [nil]
|
248
|
-
def <<(message)
|
249
|
-
@targets.each do |logger|
|
250
|
-
logger << message
|
251
|
-
logger.flush if logger.respond_to?(:flush)
|
252
|
-
end
|
253
|
-
end
|
254
|
-
|
255
|
-
# Close all logger targets
|
256
|
-
#
|
257
|
-
# @return [nil]
|
258
|
-
def close
|
259
|
-
@targets.each(&:close)
|
260
|
-
end
|
261
|
-
|
262
|
-
# Forward any unknown methods to all logger targets
|
263
|
-
#
|
264
|
-
# This allows calling standard Logger methods like info, debug, error, etc.
|
265
|
-
# directly on the MultiLogger instance.
|
266
|
-
#
|
267
|
-
# @param method [Symbol] The method name to forward
|
268
|
-
# @param args [Array] Arguments to pass to the method
|
269
|
-
# @return [nil]
|
270
|
-
def method_missing(method, ...)
|
271
|
-
@targets.each { |logger| logger.send(method, ...) }
|
272
|
-
end
|
273
|
-
|
274
|
-
# Check if all logger targets respond to a given method
|
275
|
-
#
|
276
|
-
# @param method [Symbol] The method name to check
|
277
|
-
# @param include_private [Boolean] Whether to include private methods
|
278
|
-
# @return [Boolean] True if all logger targets respond to the method
|
279
|
-
def respond_to_missing?(method, include_private = false)
|
280
|
-
@targets.all? { |logger| logger.respond_to?(method, include_private) }
|
281
|
-
end
|
282
|
-
|
283
|
-
# Create a configured logger based on options
|
284
|
-
#
|
285
|
-
# This factory method creates a logger configured with appropriate formatters
|
286
|
-
# and targets based on the provided options. By default, it creates a logger
|
287
|
-
# that writes to both stdout (with colors) and a log file (plain text).
|
288
|
-
#
|
289
|
-
# @deprecated This method is deprecated and will be removed in version 0.2.0.
|
290
|
-
# Use Makit::Logging::Logger.new with middleware instead.
|
291
|
-
#
|
292
|
-
# @param options [Hash] Logger configuration options
|
293
|
-
# @option options [Symbol] :level (:info) The log level (:debug, :info, :warn, :error, :fatal)
|
294
|
-
# @option options [Boolean] :file_logging (true) Whether to log to a file
|
295
|
-
# @option options [String] :log_file (nil) Custom log file path, defaults to rake task-based path
|
296
|
-
# @option options [Boolean] :structured_logging (false) Whether to use JSON structured logging for file output
|
297
|
-
# @return [Logger, MultiLogger] A configured logger instance
|
298
|
-
def self.create_logger(options = {})
|
299
|
-
warn "Makit::Logging::MultiLogger.create_logger is deprecated and will be removed in version 0.2.0. Use Makit::Logging::Logger.new with middleware instead."
|
300
|
-
log_level = options[:level] || DEFAULT_LOG_LEVEL
|
301
|
-
log_level = LOG_LEVELS[log_level] || LOG_LEVELS[DEFAULT_LOG_LEVEL]
|
302
|
-
|
303
|
-
stdout_logger = ::Logger.new($stdout)
|
304
|
-
stdout_logger.level = log_level
|
305
|
-
stdout_logger.formatter = ColorFormatter.new
|
306
|
-
|
307
|
-
# if clean or clobber commands are used, then log ONLY to stdout
|
308
|
-
return stdout_logger if ARGV.include?("clean") || ARGV.include?("clobber")
|
309
|
-
|
310
|
-
return stdout_logger if Makit::Environment.project_root_directory.nil?
|
311
|
-
|
312
|
-
# Create file logger if logging to file is enabled
|
313
|
-
if options[:file_logging] != false
|
314
|
-
log_filename = create_log_filename(options)
|
315
|
-
file_logger = create_file_logger(log_filename, log_level, options)
|
316
|
-
return MultiLogger.new(file_logger, stdout_logger)
|
317
|
-
end
|
318
|
-
|
319
|
-
stdout_logger
|
320
|
-
end
|
321
|
-
|
322
|
-
# Create a file logger with appropriate formatter
|
323
|
-
#
|
324
|
-
# Creates a logger that writes to a file with the specified formatter
|
325
|
-
# and log level. Ensures the directory for the log file exists.
|
326
|
-
#
|
327
|
-
# @param log_filename [String] Path where log file should be created
|
328
|
-
# @param log_level [Integer] Log level to set (from Logger constants)
|
329
|
-
# @param options [Hash] Configuration options
|
330
|
-
# @option options [Boolean] :structured_logging (false) Whether to use JSON formatted logs
|
331
|
-
# @return [Logger] Configured file logger
|
332
|
-
def self.create_file_logger(log_filename, log_level, options)
|
333
|
-
FileUtils.mkdir_p(File.dirname(log_filename))
|
334
|
-
|
335
|
-
file_logger = ::Logger.new(log_filename)
|
336
|
-
file_logger.level = log_level
|
337
|
-
|
338
|
-
# Use structured logging for file output if requested
|
339
|
-
file_logger.formatter = if options[:structured_logging]
|
340
|
-
StructuredFormatter.new
|
341
|
-
else
|
342
|
-
PlainFormatter.new
|
343
|
-
end
|
344
|
-
|
345
|
-
file_logger
|
346
|
-
end
|
347
|
-
|
348
|
-
# Determine the appropriate log filename
|
349
|
-
#
|
350
|
-
# Generates a log filename based on options and the current rake task.
|
351
|
-
# If a custom log file is specified in options, that is used. Otherwise,
|
352
|
-
# a log file is created in the artifacts directory with a name based on
|
353
|
-
# the current rake task.
|
354
|
-
#
|
355
|
-
# @param options [Hash] Configuration options
|
356
|
-
# @option options [String] :log_file (nil) Custom log file path
|
357
|
-
# @return [String] The path to use for the log file
|
358
|
-
def self.create_log_filename(options)
|
359
|
-
if options[:log_file]
|
360
|
-
options[:log_file]
|
361
|
-
elsif ARGV.empty?
|
362
|
-
"#{Makit::Environment.project_root_directory}/artifacts/rake.log"
|
363
|
-
else
|
364
|
-
task_name = ARGV.join("_").gsub(":", "_")
|
365
|
-
"#{Makit::Environment.project_root_directory}/artifacts/rake_#{task_name}.log"
|
366
|
-
end
|
367
|
-
end
|
368
|
-
end
|
369
|
-
|
370
|
-
# ===== DEPRECATED LEGACY LOGGING =====
|
371
|
-
#
|
372
|
-
# The following classes and methods are deprecated and will be removed in version 0.2.0:
|
373
|
-
# - PlainFormatter
|
374
|
-
# - ColorFormatter
|
375
|
-
# - StructuredFormatter
|
376
|
-
# - MultiLogger
|
377
|
-
# - MultiLogger.create_logger
|
378
|
-
#
|
379
|
-
# MIGRATION GUIDE:
|
380
|
-
#
|
381
|
-
# OLD (deprecated):
|
382
|
-
# logger = Makit::Logging::MultiLogger.create_logger
|
383
|
-
# logger.info("message")
|
384
|
-
#
|
385
|
-
# NEW (recommended):
|
386
|
-
# Makit::Logging.info("message") # Uses default logger
|
387
|
-
# # OR
|
388
|
-
# logger = Makit::Logging::Logger.new(sinks: [...])
|
389
|
-
# logger.info("message")
|
390
|
-
#
|
391
|
-
# For custom formatting, use sinks:
|
392
|
-
# logger = Makit::Logging::Logger.new(
|
393
|
-
# sinks: [
|
394
|
-
# Makit::Logging::Sinks::Console.new,
|
395
|
-
# Makit::Logging::Sinks::FileSink.new(log_file: "app.log")
|
396
|
-
# ]
|
397
|
-
# )
|
398
|
-
|
399
|
-
# ===== NEW LOGGING ARCHITECTURE =====
|
400
|
-
|
401
|
-
# Default logger with unified file sink
|
402
|
-
# This replaces the previous multi-sink approach with a single, configurable sink
|
403
|
-
DEFAULT_LOGGER = Logger.new(
|
404
|
-
level: current_log_level,
|
405
|
-
verbosity: current_verbosity,
|
406
|
-
sinks: [
|
407
|
-
Sinks::UnifiedFileSink.new(
|
408
|
-
configurations: [
|
409
|
-
# Console output with colors and symbols
|
410
|
-
{
|
411
|
-
file: $stdout,
|
412
|
-
format: :console,
|
413
|
-
show_timestamp: false,
|
414
|
-
show_level: false,
|
415
|
-
},
|
416
|
-
# Main log file in JSON format
|
417
|
-
{
|
418
|
-
file: "artifacts/makit.log",
|
419
|
-
format: :json,
|
420
|
-
append: true,
|
421
|
-
include_metadata: true,
|
422
|
-
},
|
423
|
-
# Debug log file in text format
|
424
|
-
{
|
425
|
-
file: "artifacts/debug.log",
|
426
|
-
format: :text,
|
427
|
-
append: true,
|
428
|
-
min_level: :debug,
|
429
|
-
include_context: true,
|
430
|
-
},
|
431
|
-
],
|
432
|
-
),
|
433
|
-
],
|
434
|
-
)
|
435
|
-
|
436
|
-
# Convenience methods that delegate to the default logger
|
437
|
-
# These provide a simple API for common logging operations
|
438
|
-
|
439
|
-
# Log an info message
|
440
|
-
#
|
441
|
-
# @param message [String] the log message
|
442
|
-
# @param context [Hash] additional context information
|
443
|
-
# @return [void]
|
444
|
-
def self.info(message, context = {})
|
445
|
-
DEFAULT_LOGGER.info(message, context)
|
446
|
-
end
|
447
|
-
|
448
|
-
# Log a success message
|
449
|
-
#
|
450
|
-
# @param message [String] the log message
|
451
|
-
# @param context [Hash] additional context information
|
452
|
-
# @return [void]
|
453
|
-
def self.success(message, context = {})
|
454
|
-
DEFAULT_LOGGER.success(message, context)
|
455
|
-
end
|
456
|
-
|
457
|
-
# Log an error message
|
458
|
-
#
|
459
|
-
# @param message [String] the log message
|
460
|
-
# @param context [Hash] additional context information
|
461
|
-
# @return [void]
|
462
|
-
def self.error(message, context = {})
|
463
|
-
DEFAULT_LOGGER.error(message, context)
|
464
|
-
end
|
465
|
-
|
466
|
-
# Log a warning message
|
467
|
-
#
|
468
|
-
# @param message [String] the log message
|
469
|
-
# @param context [Hash] additional context information
|
470
|
-
# @return [void]
|
471
|
-
def self.warn(message, context = {})
|
472
|
-
DEFAULT_LOGGER.warn(message, context)
|
473
|
-
end
|
474
|
-
|
475
|
-
# Log a debug message
|
476
|
-
#
|
477
|
-
# @param message [String] the log message
|
478
|
-
# @param context [Hash] additional context information
|
479
|
-
# @return [void]
|
480
|
-
def self.debug(message, context = {})
|
481
|
-
DEFAULT_LOGGER.debug(message, context)
|
482
|
-
end
|
483
|
-
|
484
|
-
# Log a fatal message
|
485
|
-
#
|
486
|
-
# @param message [String] the log message
|
487
|
-
# @param context [Hash] additional context information
|
488
|
-
# @return [void]
|
489
|
-
def self.fatal(message, context = {})
|
490
|
-
DEFAULT_LOGGER.fatal(message, context)
|
491
|
-
end
|
492
|
-
|
493
|
-
# Log a verbose message (only shown in verbose or debug mode)
|
494
|
-
#
|
495
|
-
# @param message [String] the log message
|
496
|
-
# @param context [Hash] additional context information
|
497
|
-
# @return [void]
|
498
|
-
def self.verbose(message, context = {})
|
499
|
-
DEFAULT_LOGGER.verbose(message, context)
|
500
|
-
end
|
501
|
-
|
502
|
-
# Log a quiet message (shown even in quiet mode)
|
503
|
-
#
|
504
|
-
# @param message [String] the log message
|
505
|
-
# @param context [Hash] additional context information
|
506
|
-
# @return [void]
|
507
|
-
def self.quiet(message, context = {})
|
508
|
-
DEFAULT_LOGGER.quiet(message, context)
|
509
|
-
end
|
510
|
-
|
511
|
-
# Create a logger with environment-specific configuration
|
512
|
-
#
|
513
|
-
# @param environment [Symbol] environment name (:development, :production, :test, :ci)
|
514
|
-
# @return [Logger] configured logger instance
|
515
|
-
def self.create_logger(environment: :default)
|
516
|
-
config = case environment
|
517
|
-
when :development
|
518
|
-
Configuration.development_config
|
519
|
-
when :production
|
520
|
-
Configuration.production_config
|
521
|
-
when :test
|
522
|
-
Configuration.test_config
|
523
|
-
when :ci
|
524
|
-
Configuration.ci_config
|
525
|
-
else
|
526
|
-
Configuration.default_config
|
527
|
-
end
|
528
|
-
|
529
|
-
Logger.new(
|
530
|
-
sinks: [
|
531
|
-
Sinks::UnifiedFileSink.new(configurations: config.configurations),
|
532
|
-
],
|
533
|
-
)
|
534
|
-
end
|
535
|
-
|
536
|
-
# Create a logger from configuration file
|
537
|
-
#
|
538
|
-
# @param config_file [String] path to configuration file (YAML or JSON)
|
539
|
-
# @return [Logger] configured logger instance
|
540
|
-
def self.create_logger_from_file(config_file)
|
541
|
-
config = if config_file.end_with?(".yaml") || config_file.end_with?(".yml")
|
542
|
-
Configuration.from_yaml(config_file)
|
543
|
-
elsif config_file.end_with?(".json")
|
544
|
-
Configuration.from_json(config_file)
|
545
|
-
else
|
546
|
-
raise ArgumentError, "Configuration file must be YAML (.yaml/.yml) or JSON (.json)"
|
547
|
-
end
|
548
|
-
|
549
|
-
config.validate!
|
550
|
-
|
551
|
-
Logger.new(
|
552
|
-
sinks: [
|
553
|
-
Sinks::UnifiedFileSink.new(configurations: config.configurations),
|
554
|
-
],
|
555
|
-
)
|
556
|
-
end
|
557
|
-
|
558
|
-
# Get the default logger instance
|
559
|
-
#
|
560
|
-
# @return [Logger] the default logger
|
561
|
-
def self.default_logger
|
562
|
-
DEFAULT_LOGGER
|
563
|
-
end
|
564
|
-
end
|
565
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "logger"
|
4
|
+
begin
|
5
|
+
require "colorize"
|
6
|
+
rescue LoadError
|
7
|
+
# colorize gem not available, define a no-op colorize method
|
8
|
+
class String
|
9
|
+
def colorize(*_args)
|
10
|
+
self
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
require_relative "symbols"
|
15
|
+
require_relative "logging/logger"
|
16
|
+
require_relative "logging/log_request"
|
17
|
+
require_relative "logging/sinks/base"
|
18
|
+
require_relative "logging/sinks/console"
|
19
|
+
require_relative "logging/sinks/file_sink"
|
20
|
+
require_relative "logging/sinks/structured"
|
21
|
+
require_relative "logging/sinks/unified_file_sink"
|
22
|
+
require_relative "logging/configuration"
|
23
|
+
|
24
|
+
# This module provides classes for the Makit gem.
|
25
|
+
module Makit
|
26
|
+
# Logging infrastructure for the Makit gem
|
27
|
+
#
|
28
|
+
# This module provides a comprehensive logging system with multiple formatters,
|
29
|
+
# multi-target output capabilities, and configurable log levels. It supports:
|
30
|
+
#
|
31
|
+
# - Plain text logging (suitable for files)
|
32
|
+
# - Colored console output (improved terminal readability)
|
33
|
+
# - Structured JSON logging (machine-parsable format)
|
34
|
+
# - Multi-target logging (write to multiple destinations simultaneously)
|
35
|
+
# - Sink-based output processing (similar to Commands::Runner)
|
36
|
+
#
|
37
|
+
# @deprecated The legacy MultiLogger, Formatter classes, and create_logger method
|
38
|
+
# are deprecated and will be removed in version 0.2.0. Use the new Logger class
|
39
|
+
# with sinks instead.
|
40
|
+
#
|
41
|
+
# @example Basic usage with new architecture (recommended)
|
42
|
+
# Makit::Logging.info("Application started")
|
43
|
+
# Makit::Logging.success("Build completed")
|
44
|
+
# Makit::Logging.error("Something went wrong")
|
45
|
+
#
|
46
|
+
# @example Custom logger configuration
|
47
|
+
# logger = Makit::Logging::Logger.new(
|
48
|
+
# sinks: [
|
49
|
+
# Makit::Logging::Sinks::Console.new,
|
50
|
+
# Makit::Logging::Sinks::FileSink.new(log_file: "custom.log")
|
51
|
+
# ]
|
52
|
+
# )
|
53
|
+
# logger.info("Custom message")
|
54
|
+
#
|
55
|
+
# @example Legacy usage (deprecated - will be removed in v0.2.0)
|
56
|
+
# logger = Makit::Logging::MultiLogger.create_logger
|
57
|
+
# logger.info("Application started")
|
58
|
+
# logger.error("Something went wrong")
|
59
|
+
module Logging
|
60
|
+
ANSI_COLOR_REGEX = /\e\[[0-9;]*m/
|
61
|
+
|
62
|
+
# Log levels that can be configured
|
63
|
+
LOG_LEVELS = {
|
64
|
+
debug: ::Logger::DEBUG,
|
65
|
+
info: ::Logger::INFO,
|
66
|
+
warn: ::Logger::WARN,
|
67
|
+
error: ::Logger::ERROR,
|
68
|
+
fatal: ::Logger::FATAL,
|
69
|
+
}.freeze
|
70
|
+
|
71
|
+
# Default log level
|
72
|
+
DEFAULT_LOG_LEVEL = :info
|
73
|
+
|
74
|
+
# Get the current log level from environment or use default
|
75
|
+
def self.current_log_level
|
76
|
+
env_level = ENV["LOG_LEVEL"]&.downcase&.to_sym
|
77
|
+
return env_level if env_level && LOG_LEVELS.key?(env_level)
|
78
|
+
|
79
|
+
DEFAULT_LOG_LEVEL
|
80
|
+
end
|
81
|
+
|
82
|
+
# Get the current verbosity level from environment or use default
|
83
|
+
def self.current_verbosity
|
84
|
+
env_verbosity = ENV["VERBOSITY"]&.downcase&.to_sym
|
85
|
+
return env_verbosity if env_verbosity && %i[quiet normal verbose debug].include?(env_verbosity)
|
86
|
+
|
87
|
+
:normal
|
88
|
+
end
|
89
|
+
|
90
|
+
# Get the current verbosity level from the default logger
|
91
|
+
#
|
92
|
+
# @return [Symbol] current verbosity level (:quiet, :normal, :verbose, :debug)
|
93
|
+
def self.verbosity
|
94
|
+
DEFAULT_LOGGER.verbosity
|
95
|
+
end
|
96
|
+
|
97
|
+
# Logs the duration of a rake task to a file
|
98
|
+
#
|
99
|
+
# This method calculates the elapsed time since the STARTTIME constant was set
|
100
|
+
# and appends this information to a log file. Used to track performance of rake tasks.
|
101
|
+
#
|
102
|
+
# @return [nil]
|
103
|
+
def self.log_rake_duration
|
104
|
+
# use the STARTTIME constant to log the duration of the rake task
|
105
|
+
# to the log/rake.duration.txt file
|
106
|
+
duration = Time.now - STARTTIME
|
107
|
+
FileUtils.mkdir_p("log")
|
108
|
+
File.open("log/rake.duration.txt", "a") do |file|
|
109
|
+
file.puts "Rake task duration: #{duration} seconds"
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
# Plain text log formatter that strips ANSI color codes
|
114
|
+
#
|
115
|
+
# This formatter removes color codes from log messages and provides
|
116
|
+
# clean, plain text output suitable for file logging or systems
|
117
|
+
# that don't support color output.
|
118
|
+
#
|
119
|
+
# @deprecated This class is deprecated and will be removed in version 0.2.0.
|
120
|
+
# Use Makit::Logging::Logger with Makit::Logging::Sinks::FileSink instead.
|
121
|
+
class PlainFormatter < ::Logger::Formatter
|
122
|
+
# Format a log message as plain text
|
123
|
+
#
|
124
|
+
# @param severity [String] log level (DEBUG, INFO, WARN, ERROR, FATAL)
|
125
|
+
# @param time [Time] timestamp of the log message
|
126
|
+
# @param _progname [String] program name (unused)
|
127
|
+
# @param msg [String] the log message content
|
128
|
+
# @return [String] formatted plain text log entry
|
129
|
+
def call(severity, time, _progname, msg)
|
130
|
+
warn "Makit::Logging::PlainFormatter is deprecated and will be removed in version 0.2.0. Use Makit::Logging::Logger with Makit::Logging::Sinks::FileSink instead."
|
131
|
+
stripped_msg = msg.gsub(ANSI_COLOR_REGEX, "") # Remove ANSI color codes
|
132
|
+
timestamp = time.strftime("%Y-%m-%d %H:%M:%S")
|
133
|
+
"[#{timestamp}] #{severity}: #{stripped_msg}\n"
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# Colored log formatter for terminal output
|
138
|
+
#
|
139
|
+
# This formatter adds appropriate colors to different log levels
|
140
|
+
# to improve readability in terminal environments. Colors are:
|
141
|
+
# DEBUG (light blue), INFO (green), WARN (yellow), ERROR (red), FATAL (bold red)
|
142
|
+
#
|
143
|
+
# @deprecated This class is deprecated and will be removed in version 0.2.0.
|
144
|
+
# Use Makit::Logging::Logger with Makit::Logging::Sinks::Console instead.
|
145
|
+
class ColorFormatter < ::Logger::Formatter
|
146
|
+
# Format a log message with colors
|
147
|
+
#
|
148
|
+
# @param severity [String] log level (DEBUG, INFO, WARN, ERROR, FATAL)
|
149
|
+
# @param time [Time] timestamp of the log message
|
150
|
+
# @param _progname [String] program name (unused)
|
151
|
+
# @param msg [String] the log message content
|
152
|
+
# @return [String] formatted colored log entry
|
153
|
+
def call(severity, time, _progname, msg)
|
154
|
+
warn "Makit::Logging::ColorFormatter is deprecated and will be removed in version 0.2.0. Use Makit::Logging::Logger with Makit::Logging::Sinks::Console instead."
|
155
|
+
timestamp = time.strftime("%Y-%m-%d %H:%M:%S")
|
156
|
+
colored_severity = colorize_severity(severity)
|
157
|
+
"[#{timestamp}] #{colored_severity}: #{msg}\n"
|
158
|
+
end
|
159
|
+
|
160
|
+
private
|
161
|
+
|
162
|
+
def colorize_severity(severity)
|
163
|
+
case severity
|
164
|
+
when "DEBUG"
|
165
|
+
severity.light_blue
|
166
|
+
when "INFO"
|
167
|
+
severity.green
|
168
|
+
when "WARN"
|
169
|
+
severity.yellow
|
170
|
+
when "ERROR"
|
171
|
+
severity.red
|
172
|
+
when "FATAL"
|
173
|
+
severity.red.bold
|
174
|
+
else
|
175
|
+
severity
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
# Structured JSON log formatter
|
181
|
+
#
|
182
|
+
# This formatter outputs log messages as JSON objects with structured
|
183
|
+
# fields including timestamp, level, message, and program name.
|
184
|
+
# Useful for log aggregation systems and machine parsing.
|
185
|
+
#
|
186
|
+
# @deprecated This class is deprecated and will be removed in version 0.2.0.
|
187
|
+
# Use Makit::Logging::Logger with Makit::Logging::Sinks::FileSink (formatter: :json) instead.
|
188
|
+
class StructuredFormatter < ::Logger::Formatter
|
189
|
+
# Format a log message as JSON
|
190
|
+
#
|
191
|
+
# @param severity [String] log level (DEBUG, INFO, WARN, ERROR, FATAL)
|
192
|
+
# @param time [Time] timestamp of the log message
|
193
|
+
# @param progname [String] program name
|
194
|
+
# @param msg [String] the log message content
|
195
|
+
# @return [String] JSON formatted log entry with newline
|
196
|
+
def call(severity, time, progname, msg)
|
197
|
+
warn "Makit::Logging::StructuredFormatter is deprecated and will be removed in version 0.2.0. Use Makit::Logging::Logger with Makit::Logging::Sinks::FileSink (formatter: :json) instead."
|
198
|
+
timestamp = time.strftime("%Y-%m-%d %H:%M:%S.%L")
|
199
|
+
{
|
200
|
+
timestamp: timestamp,
|
201
|
+
level: severity,
|
202
|
+
message: msg,
|
203
|
+
progname: progname,
|
204
|
+
}.to_json + "\n"
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
# Multi-target logger that writes to multiple destinations
|
209
|
+
#
|
210
|
+
# This logger allows writing log messages to multiple targets simultaneously,
|
211
|
+
# such as both stdout and a file, or multiple files with different formats.
|
212
|
+
#
|
213
|
+
# @deprecated This class is deprecated and will be removed in version 0.2.0.
|
214
|
+
# Use Makit::Logging::Logger with multiple middleware instead.
|
215
|
+
#
|
216
|
+
# @example Create a logger that writes to both console and file
|
217
|
+
# stdout_logger = Logger.new($stdout)
|
218
|
+
# file_logger = Logger.new("app.log")
|
219
|
+
# multi_logger = MultiLogger.new(stdout_logger, file_logger)
|
220
|
+
# multi_logger.info("This goes to both destinations")
|
221
|
+
class MultiLogger
|
222
|
+
# Initialize a new MultiLogger with multiple logging targets
|
223
|
+
#
|
224
|
+
# @param targets [Array<Logger>] One or more logger instances to write to
|
225
|
+
def initialize(*targets)
|
226
|
+
warn "Makit::Logging::MultiLogger is deprecated and will be removed in version 0.2.0. Use Makit::Logging::Logger with middleware instead."
|
227
|
+
@targets = targets
|
228
|
+
end
|
229
|
+
|
230
|
+
# Add a message to all logger targets
|
231
|
+
#
|
232
|
+
# @param severity [Integer] The severity level (::Logger::DEBUG, ::Logger::INFO, etc.)
|
233
|
+
# @param message [String, nil] The message to log (or nil if using block)
|
234
|
+
# @param progname [String, nil] The program name to include in the log
|
235
|
+
# @param block [Proc, nil] Optional block that returns the message to log
|
236
|
+
# @return [nil]
|
237
|
+
def add(severity, message = nil, progname = nil, &block)
|
238
|
+
@targets.each do |logger|
|
239
|
+
logger.add(severity, message, progname, &block)
|
240
|
+
logger.flush if logger.respond_to?(:flush)
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
# Append a message directly to all logger targets
|
245
|
+
#
|
246
|
+
# @param message [String] The message to append to all loggers
|
247
|
+
# @return [nil]
|
248
|
+
def <<(message)
|
249
|
+
@targets.each do |logger|
|
250
|
+
logger << message
|
251
|
+
logger.flush if logger.respond_to?(:flush)
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
# Close all logger targets
|
256
|
+
#
|
257
|
+
# @return [nil]
|
258
|
+
def close
|
259
|
+
@targets.each(&:close)
|
260
|
+
end
|
261
|
+
|
262
|
+
# Forward any unknown methods to all logger targets
|
263
|
+
#
|
264
|
+
# This allows calling standard Logger methods like info, debug, error, etc.
|
265
|
+
# directly on the MultiLogger instance.
|
266
|
+
#
|
267
|
+
# @param method [Symbol] The method name to forward
|
268
|
+
# @param args [Array] Arguments to pass to the method
|
269
|
+
# @return [nil]
|
270
|
+
def method_missing(method, ...)
|
271
|
+
@targets.each { |logger| logger.send(method, ...) }
|
272
|
+
end
|
273
|
+
|
274
|
+
# Check if all logger targets respond to a given method
|
275
|
+
#
|
276
|
+
# @param method [Symbol] The method name to check
|
277
|
+
# @param include_private [Boolean] Whether to include private methods
|
278
|
+
# @return [Boolean] True if all logger targets respond to the method
|
279
|
+
def respond_to_missing?(method, include_private = false)
|
280
|
+
@targets.all? { |logger| logger.respond_to?(method, include_private) }
|
281
|
+
end
|
282
|
+
|
283
|
+
# Create a configured logger based on options
|
284
|
+
#
|
285
|
+
# This factory method creates a logger configured with appropriate formatters
|
286
|
+
# and targets based on the provided options. By default, it creates a logger
|
287
|
+
# that writes to both stdout (with colors) and a log file (plain text).
|
288
|
+
#
|
289
|
+
# @deprecated This method is deprecated and will be removed in version 0.2.0.
|
290
|
+
# Use Makit::Logging::Logger.new with middleware instead.
|
291
|
+
#
|
292
|
+
# @param options [Hash] Logger configuration options
|
293
|
+
# @option options [Symbol] :level (:info) The log level (:debug, :info, :warn, :error, :fatal)
|
294
|
+
# @option options [Boolean] :file_logging (true) Whether to log to a file
|
295
|
+
# @option options [String] :log_file (nil) Custom log file path, defaults to rake task-based path
|
296
|
+
# @option options [Boolean] :structured_logging (false) Whether to use JSON structured logging for file output
|
297
|
+
# @return [Logger, MultiLogger] A configured logger instance
|
298
|
+
def self.create_logger(options = {})
|
299
|
+
warn "Makit::Logging::MultiLogger.create_logger is deprecated and will be removed in version 0.2.0. Use Makit::Logging::Logger.new with middleware instead."
|
300
|
+
log_level = options[:level] || DEFAULT_LOG_LEVEL
|
301
|
+
log_level = LOG_LEVELS[log_level] || LOG_LEVELS[DEFAULT_LOG_LEVEL]
|
302
|
+
|
303
|
+
stdout_logger = ::Logger.new($stdout)
|
304
|
+
stdout_logger.level = log_level
|
305
|
+
stdout_logger.formatter = ColorFormatter.new
|
306
|
+
|
307
|
+
# if clean or clobber commands are used, then log ONLY to stdout
|
308
|
+
return stdout_logger if ARGV.include?("clean") || ARGV.include?("clobber")
|
309
|
+
|
310
|
+
return stdout_logger if Makit::Environment.project_root_directory.nil?
|
311
|
+
|
312
|
+
# Create file logger if logging to file is enabled
|
313
|
+
if options[:file_logging] != false
|
314
|
+
log_filename = create_log_filename(options)
|
315
|
+
file_logger = create_file_logger(log_filename, log_level, options)
|
316
|
+
return MultiLogger.new(file_logger, stdout_logger)
|
317
|
+
end
|
318
|
+
|
319
|
+
stdout_logger
|
320
|
+
end
|
321
|
+
|
322
|
+
# Create a file logger with appropriate formatter
|
323
|
+
#
|
324
|
+
# Creates a logger that writes to a file with the specified formatter
|
325
|
+
# and log level. Ensures the directory for the log file exists.
|
326
|
+
#
|
327
|
+
# @param log_filename [String] Path where log file should be created
|
328
|
+
# @param log_level [Integer] Log level to set (from Logger constants)
|
329
|
+
# @param options [Hash] Configuration options
|
330
|
+
# @option options [Boolean] :structured_logging (false) Whether to use JSON formatted logs
|
331
|
+
# @return [Logger] Configured file logger
|
332
|
+
def self.create_file_logger(log_filename, log_level, options)
|
333
|
+
FileUtils.mkdir_p(File.dirname(log_filename))
|
334
|
+
|
335
|
+
file_logger = ::Logger.new(log_filename)
|
336
|
+
file_logger.level = log_level
|
337
|
+
|
338
|
+
# Use structured logging for file output if requested
|
339
|
+
file_logger.formatter = if options[:structured_logging]
|
340
|
+
StructuredFormatter.new
|
341
|
+
else
|
342
|
+
PlainFormatter.new
|
343
|
+
end
|
344
|
+
|
345
|
+
file_logger
|
346
|
+
end
|
347
|
+
|
348
|
+
# Determine the appropriate log filename
|
349
|
+
#
|
350
|
+
# Generates a log filename based on options and the current rake task.
|
351
|
+
# If a custom log file is specified in options, that is used. Otherwise,
|
352
|
+
# a log file is created in the artifacts directory with a name based on
|
353
|
+
# the current rake task.
|
354
|
+
#
|
355
|
+
# @param options [Hash] Configuration options
|
356
|
+
# @option options [String] :log_file (nil) Custom log file path
|
357
|
+
# @return [String] The path to use for the log file
|
358
|
+
def self.create_log_filename(options)
|
359
|
+
if options[:log_file]
|
360
|
+
options[:log_file]
|
361
|
+
elsif ARGV.empty?
|
362
|
+
"#{Makit::Environment.project_root_directory}/artifacts/rake.log"
|
363
|
+
else
|
364
|
+
task_name = ARGV.join("_").gsub(":", "_")
|
365
|
+
"#{Makit::Environment.project_root_directory}/artifacts/rake_#{task_name}.log"
|
366
|
+
end
|
367
|
+
end
|
368
|
+
end
|
369
|
+
|
370
|
+
# ===== DEPRECATED LEGACY LOGGING =====
|
371
|
+
#
|
372
|
+
# The following classes and methods are deprecated and will be removed in version 0.2.0:
|
373
|
+
# - PlainFormatter
|
374
|
+
# - ColorFormatter
|
375
|
+
# - StructuredFormatter
|
376
|
+
# - MultiLogger
|
377
|
+
# - MultiLogger.create_logger
|
378
|
+
#
|
379
|
+
# MIGRATION GUIDE:
|
380
|
+
#
|
381
|
+
# OLD (deprecated):
|
382
|
+
# logger = Makit::Logging::MultiLogger.create_logger
|
383
|
+
# logger.info("message")
|
384
|
+
#
|
385
|
+
# NEW (recommended):
|
386
|
+
# Makit::Logging.info("message") # Uses default logger
|
387
|
+
# # OR
|
388
|
+
# logger = Makit::Logging::Logger.new(sinks: [...])
|
389
|
+
# logger.info("message")
|
390
|
+
#
|
391
|
+
# For custom formatting, use sinks:
|
392
|
+
# logger = Makit::Logging::Logger.new(
|
393
|
+
# sinks: [
|
394
|
+
# Makit::Logging::Sinks::Console.new,
|
395
|
+
# Makit::Logging::Sinks::FileSink.new(log_file: "app.log")
|
396
|
+
# ]
|
397
|
+
# )
|
398
|
+
|
399
|
+
# ===== NEW LOGGING ARCHITECTURE =====
|
400
|
+
|
401
|
+
# Default logger with unified file sink
|
402
|
+
# This replaces the previous multi-sink approach with a single, configurable sink
|
403
|
+
DEFAULT_LOGGER = Logger.new(
|
404
|
+
level: current_log_level,
|
405
|
+
verbosity: current_verbosity,
|
406
|
+
sinks: [
|
407
|
+
Sinks::UnifiedFileSink.new(
|
408
|
+
configurations: [
|
409
|
+
# Console output with colors and symbols
|
410
|
+
{
|
411
|
+
file: $stdout,
|
412
|
+
format: :console,
|
413
|
+
show_timestamp: false,
|
414
|
+
show_level: false,
|
415
|
+
},
|
416
|
+
# Main log file in JSON format
|
417
|
+
{
|
418
|
+
file: "artifacts/makit.log",
|
419
|
+
format: :json,
|
420
|
+
append: true,
|
421
|
+
include_metadata: true,
|
422
|
+
},
|
423
|
+
# Debug log file in text format
|
424
|
+
{
|
425
|
+
file: "artifacts/debug.log",
|
426
|
+
format: :text,
|
427
|
+
append: true,
|
428
|
+
min_level: :debug,
|
429
|
+
include_context: true,
|
430
|
+
},
|
431
|
+
],
|
432
|
+
),
|
433
|
+
],
|
434
|
+
)
|
435
|
+
|
436
|
+
# Convenience methods that delegate to the default logger
|
437
|
+
# These provide a simple API for common logging operations
|
438
|
+
|
439
|
+
# Log an info message
|
440
|
+
#
|
441
|
+
# @param message [String] the log message
|
442
|
+
# @param context [Hash] additional context information
|
443
|
+
# @return [void]
|
444
|
+
def self.info(message, context = {})
|
445
|
+
DEFAULT_LOGGER.info(message, context)
|
446
|
+
end
|
447
|
+
|
448
|
+
# Log a success message
|
449
|
+
#
|
450
|
+
# @param message [String] the log message
|
451
|
+
# @param context [Hash] additional context information
|
452
|
+
# @return [void]
|
453
|
+
def self.success(message, context = {})
|
454
|
+
DEFAULT_LOGGER.success(message, context)
|
455
|
+
end
|
456
|
+
|
457
|
+
# Log an error message
|
458
|
+
#
|
459
|
+
# @param message [String] the log message
|
460
|
+
# @param context [Hash] additional context information
|
461
|
+
# @return [void]
|
462
|
+
def self.error(message, context = {})
|
463
|
+
DEFAULT_LOGGER.error(message, context)
|
464
|
+
end
|
465
|
+
|
466
|
+
# Log a warning message
|
467
|
+
#
|
468
|
+
# @param message [String] the log message
|
469
|
+
# @param context [Hash] additional context information
|
470
|
+
# @return [void]
|
471
|
+
def self.warn(message, context = {})
|
472
|
+
DEFAULT_LOGGER.warn(message, context)
|
473
|
+
end
|
474
|
+
|
475
|
+
# Log a debug message
|
476
|
+
#
|
477
|
+
# @param message [String] the log message
|
478
|
+
# @param context [Hash] additional context information
|
479
|
+
# @return [void]
|
480
|
+
def self.debug(message, context = {})
|
481
|
+
DEFAULT_LOGGER.debug(message, context)
|
482
|
+
end
|
483
|
+
|
484
|
+
# Log a fatal message
|
485
|
+
#
|
486
|
+
# @param message [String] the log message
|
487
|
+
# @param context [Hash] additional context information
|
488
|
+
# @return [void]
|
489
|
+
def self.fatal(message, context = {})
|
490
|
+
DEFAULT_LOGGER.fatal(message, context)
|
491
|
+
end
|
492
|
+
|
493
|
+
# Log a verbose message (only shown in verbose or debug mode)
|
494
|
+
#
|
495
|
+
# @param message [String] the log message
|
496
|
+
# @param context [Hash] additional context information
|
497
|
+
# @return [void]
|
498
|
+
def self.verbose(message, context = {})
|
499
|
+
DEFAULT_LOGGER.verbose(message, context)
|
500
|
+
end
|
501
|
+
|
502
|
+
# Log a quiet message (shown even in quiet mode)
|
503
|
+
#
|
504
|
+
# @param message [String] the log message
|
505
|
+
# @param context [Hash] additional context information
|
506
|
+
# @return [void]
|
507
|
+
def self.quiet(message, context = {})
|
508
|
+
DEFAULT_LOGGER.quiet(message, context)
|
509
|
+
end
|
510
|
+
|
511
|
+
# Create a logger with environment-specific configuration
|
512
|
+
#
|
513
|
+
# @param environment [Symbol] environment name (:development, :production, :test, :ci)
|
514
|
+
# @return [Logger] configured logger instance
|
515
|
+
def self.create_logger(environment: :default)
|
516
|
+
config = case environment
|
517
|
+
when :development
|
518
|
+
Configuration.development_config
|
519
|
+
when :production
|
520
|
+
Configuration.production_config
|
521
|
+
when :test
|
522
|
+
Configuration.test_config
|
523
|
+
when :ci
|
524
|
+
Configuration.ci_config
|
525
|
+
else
|
526
|
+
Configuration.default_config
|
527
|
+
end
|
528
|
+
|
529
|
+
Logger.new(
|
530
|
+
sinks: [
|
531
|
+
Sinks::UnifiedFileSink.new(configurations: config.configurations),
|
532
|
+
],
|
533
|
+
)
|
534
|
+
end
|
535
|
+
|
536
|
+
# Create a logger from configuration file
|
537
|
+
#
|
538
|
+
# @param config_file [String] path to configuration file (YAML or JSON)
|
539
|
+
# @return [Logger] configured logger instance
|
540
|
+
def self.create_logger_from_file(config_file)
|
541
|
+
config = if config_file.end_with?(".yaml") || config_file.end_with?(".yml")
|
542
|
+
Configuration.from_yaml(config_file)
|
543
|
+
elsif config_file.end_with?(".json")
|
544
|
+
Configuration.from_json(config_file)
|
545
|
+
else
|
546
|
+
raise ArgumentError, "Configuration file must be YAML (.yaml/.yml) or JSON (.json)"
|
547
|
+
end
|
548
|
+
|
549
|
+
config.validate!
|
550
|
+
|
551
|
+
Logger.new(
|
552
|
+
sinks: [
|
553
|
+
Sinks::UnifiedFileSink.new(configurations: config.configurations),
|
554
|
+
],
|
555
|
+
)
|
556
|
+
end
|
557
|
+
|
558
|
+
# Get the default logger instance
|
559
|
+
#
|
560
|
+
# @return [Logger] the default logger
|
561
|
+
def self.default_logger
|
562
|
+
DEFAULT_LOGGER
|
563
|
+
end
|
564
|
+
end
|
565
|
+
end
|