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,323 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base"
|
4
|
+
require_relative "../../logging/logger"
|
5
|
+
|
6
|
+
module Makit
|
7
|
+
module Commands
|
8
|
+
module Middleware
|
9
|
+
# Command-specific logging middleware with enhanced output handling
|
10
|
+
#
|
11
|
+
# This middleware provides specialized logging for command execution with
|
12
|
+
# enhanced output handling, performance tracking, and structured data
|
13
|
+
# logging. It's designed to work alongside the base Logger middleware
|
14
|
+
# to provide comprehensive command execution logging.
|
15
|
+
#
|
16
|
+
# @example Basic usage
|
17
|
+
# logger = CommandLogger.new
|
18
|
+
# runner = Runner.new(middleware: [logger])
|
19
|
+
# result = runner.execute("git --version")
|
20
|
+
#
|
21
|
+
# @example With custom configuration
|
22
|
+
# logger = CommandLogger.new(
|
23
|
+
# log_stdout: true,
|
24
|
+
# log_stderr: true,
|
25
|
+
# log_performance: true,
|
26
|
+
# max_output_lines: 50
|
27
|
+
# )
|
28
|
+
class CommandLogger < Base
|
29
|
+
# @!attribute [r] logger
|
30
|
+
# @return [Makit::Logging::Logger] the logging instance
|
31
|
+
attr_reader :logger
|
32
|
+
|
33
|
+
# Initialize command logging middleware.
|
34
|
+
#
|
35
|
+
# @param logger [Makit::Logging::Logger, nil] custom logger instance
|
36
|
+
# @param log_stdout [Boolean] whether to log stdout output
|
37
|
+
# @param log_stderr [Boolean] whether to log stderr output
|
38
|
+
# @param log_performance [Boolean] whether to log performance metrics
|
39
|
+
# @param max_output_lines [Integer] maximum lines of output to log
|
40
|
+
# @param log_level [Symbol] log level for command events
|
41
|
+
def initialize(
|
42
|
+
logger: nil,
|
43
|
+
log_stdout: false,
|
44
|
+
log_stderr: true,
|
45
|
+
log_performance: true,
|
46
|
+
max_output_lines: 100,
|
47
|
+
log_level: nil
|
48
|
+
)
|
49
|
+
@log_stdout = log_stdout
|
50
|
+
@log_stderr = log_stderr
|
51
|
+
@log_performance = log_performance
|
52
|
+
@max_output_lines = max_output_lines
|
53
|
+
@log_level = log_level || Makit::Logging.current_log_level
|
54
|
+
|
55
|
+
# Use the provided logger or create a new one with the specified log level
|
56
|
+
@logger = logger || Makit::Logging::Logger.new(
|
57
|
+
level: @log_level,
|
58
|
+
sinks: Makit::Logging.default_logger.sinks,
|
59
|
+
)
|
60
|
+
end
|
61
|
+
|
62
|
+
# Execute command with enhanced logging.
|
63
|
+
#
|
64
|
+
# @param request [Request] command request to execute
|
65
|
+
# @yield [Request] yields request to next middleware
|
66
|
+
# @return [Result] execution result
|
67
|
+
def call(request, &block)
|
68
|
+
start_time = Time.now
|
69
|
+
command_id = generate_command_id
|
70
|
+
|
71
|
+
# Log command start with enhanced context
|
72
|
+
log_command_start(request, command_id)
|
73
|
+
|
74
|
+
begin
|
75
|
+
# Execute the command
|
76
|
+
result = block.call(request)
|
77
|
+
duration = Time.now - start_time
|
78
|
+
|
79
|
+
# Log command completion with performance data
|
80
|
+
log_command_completion(request, result, duration, command_id)
|
81
|
+
|
82
|
+
# Log command output if configured
|
83
|
+
log_command_output(request, result, command_id)
|
84
|
+
|
85
|
+
result
|
86
|
+
rescue => error
|
87
|
+
duration = Time.now - start_time
|
88
|
+
|
89
|
+
# Log command error with full context
|
90
|
+
log_command_error(request, error, duration, command_id)
|
91
|
+
|
92
|
+
raise
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# Check if this middleware applies to the given request.
|
97
|
+
#
|
98
|
+
# @param request [Request] command request
|
99
|
+
# @return [Boolean] true if middleware applies
|
100
|
+
def applicable?(request)
|
101
|
+
# Apply to all requests
|
102
|
+
true
|
103
|
+
end
|
104
|
+
|
105
|
+
# Get middleware configuration.
|
106
|
+
#
|
107
|
+
# @return [Hash] middleware configuration
|
108
|
+
def config
|
109
|
+
{
|
110
|
+
name: "CommandLogger",
|
111
|
+
description: "Enhanced command execution logging with output handling",
|
112
|
+
log_stdout: @log_stdout,
|
113
|
+
log_stderr: @log_stderr,
|
114
|
+
log_performance: @log_performance,
|
115
|
+
max_output_lines: @max_output_lines,
|
116
|
+
log_level: @log_level,
|
117
|
+
logger_class: @logger.class.name,
|
118
|
+
}
|
119
|
+
end
|
120
|
+
|
121
|
+
private
|
122
|
+
|
123
|
+
# Log command execution start with enhanced context.
|
124
|
+
#
|
125
|
+
# @param request [Request] command request
|
126
|
+
# @param command_id [String] unique command identifier
|
127
|
+
def log_command_start(request, command_id)
|
128
|
+
log_data = {
|
129
|
+
command_id: command_id,
|
130
|
+
command: request.command,
|
131
|
+
arguments: request.arguments,
|
132
|
+
working_directory: request.directory,
|
133
|
+
timeout: request.timeout,
|
134
|
+
environment: request.environment&.keys || [],
|
135
|
+
timestamp: Time.now.iso8601,
|
136
|
+
}
|
137
|
+
|
138
|
+
@logger.public_send(@log_level, "Command execution started", log_data)
|
139
|
+
end
|
140
|
+
|
141
|
+
# Log command execution completion with performance data.
|
142
|
+
#
|
143
|
+
# @param request [Request] command request
|
144
|
+
# @param result [Result] execution result
|
145
|
+
# @param duration [Float] execution duration
|
146
|
+
# @param command_id [String] unique command identifier
|
147
|
+
def log_command_completion(request, result, duration, command_id)
|
148
|
+
log_data = {
|
149
|
+
command_id: command_id,
|
150
|
+
command: request.command,
|
151
|
+
success: result.success?,
|
152
|
+
exit_code: result.exit_code,
|
153
|
+
duration: duration,
|
154
|
+
}
|
155
|
+
|
156
|
+
# Add performance metrics if enabled
|
157
|
+
if @log_performance
|
158
|
+
log_data.merge!(
|
159
|
+
memory_usage: get_memory_usage,
|
160
|
+
timestamp: Time.now.iso8601,
|
161
|
+
output_size: calculate_output_size(result),
|
162
|
+
)
|
163
|
+
end
|
164
|
+
|
165
|
+
# Log at appropriate level based on success
|
166
|
+
if result.success?
|
167
|
+
@logger.info("Command completed successfully", log_data)
|
168
|
+
else
|
169
|
+
@logger.warn("Command completed with errors", log_data)
|
170
|
+
end
|
171
|
+
|
172
|
+
# Log performance warnings
|
173
|
+
log_performance_warnings(request, result, duration, command_id) if @log_performance
|
174
|
+
end
|
175
|
+
|
176
|
+
# Log command output (stdout/stderr) with line limits.
|
177
|
+
#
|
178
|
+
# @param request [Request] command request
|
179
|
+
# @param result [Result] execution result
|
180
|
+
# @param command_id [String] unique command identifier
|
181
|
+
def log_command_output(request, result, command_id)
|
182
|
+
# Log stdout if enabled and present
|
183
|
+
if @log_stdout && result.stdout && !result.stdout.empty?
|
184
|
+
output_lines = result.stdout.split("\n")
|
185
|
+
truncated = output_lines.length > @max_output_lines
|
186
|
+
|
187
|
+
log_data = {
|
188
|
+
command_id: command_id,
|
189
|
+
command: request.command,
|
190
|
+
output: truncated ? output_lines.first(@max_output_lines).join("\n") : result.stdout,
|
191
|
+
total_lines: output_lines.length,
|
192
|
+
truncated: truncated,
|
193
|
+
}
|
194
|
+
|
195
|
+
@logger.debug("Command stdout", log_data)
|
196
|
+
end
|
197
|
+
|
198
|
+
# Log stderr if enabled and present
|
199
|
+
if @log_stderr && result.stderr && !result.stderr.empty?
|
200
|
+
output_lines = result.stderr.split("\n")
|
201
|
+
truncated = output_lines.length > @max_output_lines
|
202
|
+
|
203
|
+
log_data = {
|
204
|
+
command_id: command_id,
|
205
|
+
command: request.command,
|
206
|
+
output: truncated ? output_lines.first(@max_output_lines).join("\n") : result.stderr,
|
207
|
+
total_lines: output_lines.length,
|
208
|
+
truncated: truncated,
|
209
|
+
}
|
210
|
+
|
211
|
+
@logger.warn("Command stderr", log_data)
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
# Log command execution error with full context.
|
216
|
+
#
|
217
|
+
# @param request [Request] command request
|
218
|
+
# @param error [Exception] execution error
|
219
|
+
# @param duration [Float] execution duration
|
220
|
+
# @param command_id [String] unique command identifier
|
221
|
+
def log_command_error(request, error, duration, command_id)
|
222
|
+
log_data = {
|
223
|
+
command_id: command_id,
|
224
|
+
command: request.command,
|
225
|
+
arguments: request.arguments,
|
226
|
+
working_directory: request.directory,
|
227
|
+
environment: request.environment&.keys || [],
|
228
|
+
error_class: error.class.name,
|
229
|
+
error_message: error.message,
|
230
|
+
duration: duration,
|
231
|
+
backtrace: error.backtrace&.first(10),
|
232
|
+
timestamp: Time.now.iso8601,
|
233
|
+
}
|
234
|
+
|
235
|
+
@logger.error("Command execution failed", log_data)
|
236
|
+
end
|
237
|
+
|
238
|
+
# Log performance warnings for slow or resource-intensive commands.
|
239
|
+
#
|
240
|
+
# @param request [Request] command request
|
241
|
+
# @param result [Result] execution result
|
242
|
+
# @param duration [Float] execution duration
|
243
|
+
# @param command_id [String] unique command identifier
|
244
|
+
def log_performance_warnings(request, result, duration, command_id)
|
245
|
+
# Log slow commands
|
246
|
+
if duration > 5.0
|
247
|
+
@logger.warn("Slow command detected",
|
248
|
+
command_id: command_id,
|
249
|
+
command: request.command,
|
250
|
+
duration: duration,
|
251
|
+
threshold: "5.0s")
|
252
|
+
end
|
253
|
+
|
254
|
+
# Log commands with large output
|
255
|
+
output_size = calculate_output_size(result)
|
256
|
+
if output_size > 100_000 # 100KB
|
257
|
+
@logger.warn("Command with large output detected",
|
258
|
+
command_id: command_id,
|
259
|
+
command: request.command,
|
260
|
+
output_size: "#{output_size / 1024}KB",
|
261
|
+
threshold: "100KB")
|
262
|
+
end
|
263
|
+
|
264
|
+
# Log commands with high exit codes (potential errors)
|
265
|
+
if result.exit_code > 0
|
266
|
+
@logger.info("Command completed with non-zero exit code",
|
267
|
+
command_id: command_id,
|
268
|
+
command: request.command,
|
269
|
+
exit_code: result.exit_code,
|
270
|
+
success: result.success?)
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
# Calculate total output size (stdout + stderr).
|
275
|
+
#
|
276
|
+
# @param result [Result] execution result
|
277
|
+
# @return [Integer] total output size in bytes
|
278
|
+
def calculate_output_size(result)
|
279
|
+
size = 0
|
280
|
+
size += result.stdout&.bytesize || 0
|
281
|
+
size += result.stderr&.bytesize || 0
|
282
|
+
size
|
283
|
+
end
|
284
|
+
|
285
|
+
# Generate a unique command identifier.
|
286
|
+
#
|
287
|
+
# @return [String] unique command ID
|
288
|
+
def generate_command_id
|
289
|
+
"#{::Process.pid}-#{Time.now.to_f}-#{rand(1000)}"
|
290
|
+
end
|
291
|
+
|
292
|
+
# Get current memory usage (if available).
|
293
|
+
#
|
294
|
+
# @return [String, nil] memory usage string or nil if unavailable
|
295
|
+
def get_memory_usage
|
296
|
+
# Try to get memory usage on different platforms
|
297
|
+
if RUBY_PLATFORM.match?(/mswin|mingw/)
|
298
|
+
# Windows - try to get memory usage
|
299
|
+
begin
|
300
|
+
# This is a simplified approach for Windows
|
301
|
+
"Unknown"
|
302
|
+
rescue
|
303
|
+
nil
|
304
|
+
end
|
305
|
+
else
|
306
|
+
# Unix-like systems
|
307
|
+
begin
|
308
|
+
# Try to get memory usage from /proc/self/status
|
309
|
+
if File.exist?("/proc/self/status")
|
310
|
+
status = File.read("/proc/self/status")
|
311
|
+
if match = status.match(/VmRSS:\s+(\d+)\s+kB/)
|
312
|
+
"#{match[1].to_i / 1024}MB"
|
313
|
+
end
|
314
|
+
end
|
315
|
+
rescue
|
316
|
+
nil
|
317
|
+
end
|
318
|
+
end
|
319
|
+
end
|
320
|
+
end
|
321
|
+
end
|
322
|
+
end
|
323
|
+
end
|
@@ -0,0 +1,243 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base"
|
4
|
+
|
5
|
+
module Makit
|
6
|
+
module Commands
|
7
|
+
module Middleware
|
8
|
+
# Unified logging middleware that consolidates all command logging functionality
|
9
|
+
#
|
10
|
+
# This middleware replaces the need for multiple separate logging middleware
|
11
|
+
# by providing a single, comprehensive logging solution that handles console
|
12
|
+
# display, file logging, and structured logging through the Makit::Logging system.
|
13
|
+
#
|
14
|
+
# @example Basic usage
|
15
|
+
# logger = UnifiedLogger.new
|
16
|
+
# runner = Runner.new(middleware: [logger])
|
17
|
+
# result = runner.execute("git --version")
|
18
|
+
#
|
19
|
+
# @example With custom logger configuration
|
20
|
+
# custom_logger = Makit::Logging::Logger.new(
|
21
|
+
# sinks: [
|
22
|
+
# Makit::Logging::Sinks::Console.new,
|
23
|
+
# Makit::Logging::Sinks::FileSink.new(log_file: "artifacts/commands.log")
|
24
|
+
# ]
|
25
|
+
# )
|
26
|
+
# logger = UnifiedLogger.new(logger: custom_logger)
|
27
|
+
# runner = Runner.new(middleware: [logger])
|
28
|
+
class UnifiedLogger < Base
|
29
|
+
# @!attribute [r] logger
|
30
|
+
# @return [Makit::Logging::Logger] the logging instance
|
31
|
+
attr_reader :logger
|
32
|
+
|
33
|
+
# Initialize unified logging middleware.
|
34
|
+
#
|
35
|
+
# @param logger [Makit::Logging::Logger, nil] custom logger instance
|
36
|
+
# @param log_to_console [Boolean] whether to log to console
|
37
|
+
# @param log_to_file [Boolean] whether to log to file
|
38
|
+
# @param log_performance [Boolean] whether to log performance metrics
|
39
|
+
# @param log_output [Boolean] whether to log command output
|
40
|
+
def initialize(logger: nil, log_to_console: true, log_to_file: true, log_performance: true, log_output: false)
|
41
|
+
@logger = logger || create_default_logger(log_to_console, log_to_file)
|
42
|
+
@log_performance = log_performance
|
43
|
+
@log_output = log_output
|
44
|
+
end
|
45
|
+
|
46
|
+
# Execute command with unified logging.
|
47
|
+
#
|
48
|
+
# @param request [Request] command request to execute
|
49
|
+
# @yield [Request] yields request to next middleware
|
50
|
+
# @return [Result] execution result
|
51
|
+
def call(request, &block)
|
52
|
+
command_id = generate_command_id
|
53
|
+
start_time = Time.now
|
54
|
+
|
55
|
+
# Log command start
|
56
|
+
log_command_start(request, command_id)
|
57
|
+
|
58
|
+
begin
|
59
|
+
# Execute the command
|
60
|
+
result = block.call(request)
|
61
|
+
duration = Time.now - start_time
|
62
|
+
|
63
|
+
# Log command completion
|
64
|
+
log_command_completion(request, result, duration, command_id)
|
65
|
+
|
66
|
+
result
|
67
|
+
rescue => error
|
68
|
+
duration = Time.now - start_time
|
69
|
+
|
70
|
+
# Log command error
|
71
|
+
log_command_error(request, error, duration, command_id)
|
72
|
+
|
73
|
+
raise
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Check if this middleware applies to the given request.
|
78
|
+
#
|
79
|
+
# @param request [Request] command request
|
80
|
+
# @return [Boolean] true if middleware applies
|
81
|
+
def applicable?(request)
|
82
|
+
true
|
83
|
+
end
|
84
|
+
|
85
|
+
# Get middleware configuration.
|
86
|
+
#
|
87
|
+
# @return [Hash] middleware configuration
|
88
|
+
def config
|
89
|
+
{
|
90
|
+
name: "UnifiedLogger",
|
91
|
+
description: "Unified logging for command execution with console and file output",
|
92
|
+
log_performance: @log_performance,
|
93
|
+
log_output: @log_output,
|
94
|
+
logger_class: @logger.class.name,
|
95
|
+
}
|
96
|
+
end
|
97
|
+
|
98
|
+
private
|
99
|
+
|
100
|
+
# Create default logger with console and file output
|
101
|
+
#
|
102
|
+
# @param log_to_console [Boolean] whether to log to console
|
103
|
+
# @param log_to_file [Boolean] whether to log to file
|
104
|
+
# @return [Makit::Logging::Logger] configured logger
|
105
|
+
def create_default_logger(log_to_console, log_to_file)
|
106
|
+
sinks = []
|
107
|
+
|
108
|
+
if log_to_console
|
109
|
+
sinks << Makit::Logging::Sinks::Console.new
|
110
|
+
end
|
111
|
+
|
112
|
+
if log_to_file
|
113
|
+
sinks << Makit::Logging::Sinks::FileSink.new(
|
114
|
+
log_file: "artifacts/commands.log",
|
115
|
+
formatter: :json,
|
116
|
+
include_metadata: true,
|
117
|
+
)
|
118
|
+
end
|
119
|
+
|
120
|
+
Makit::Logging::Logger.new(sinks: sinks)
|
121
|
+
end
|
122
|
+
|
123
|
+
# Log command execution start.
|
124
|
+
#
|
125
|
+
# @param request [Request] command request
|
126
|
+
# @param command_id [String] unique command identifier
|
127
|
+
def log_command_start(request, command_id)
|
128
|
+
@logger.info("Command execution started", {
|
129
|
+
command_id: command_id,
|
130
|
+
command: request.command,
|
131
|
+
arguments: request.arguments,
|
132
|
+
working_directory: request.directory,
|
133
|
+
timeout: request.timeout,
|
134
|
+
environment: request.environment&.keys || [],
|
135
|
+
})
|
136
|
+
end
|
137
|
+
|
138
|
+
# Log command execution completion.
|
139
|
+
#
|
140
|
+
# @param request [Request] command request
|
141
|
+
# @param result [Result] execution result
|
142
|
+
# @param duration [Float] execution duration
|
143
|
+
# @param command_id [String] unique command identifier
|
144
|
+
def log_command_completion(request, result, duration, command_id)
|
145
|
+
log_data = {
|
146
|
+
command_id: command_id,
|
147
|
+
command: request.command,
|
148
|
+
arguments: request.arguments,
|
149
|
+
success: result.success?,
|
150
|
+
exit_code: result.exit_code,
|
151
|
+
duration: duration,
|
152
|
+
working_directory: request.directory,
|
153
|
+
}
|
154
|
+
|
155
|
+
# Add performance metrics if enabled
|
156
|
+
if @log_performance
|
157
|
+
log_data.merge!(
|
158
|
+
memory_usage: get_memory_usage,
|
159
|
+
timestamp: Time.now.iso8601,
|
160
|
+
)
|
161
|
+
end
|
162
|
+
|
163
|
+
# Add output if enabled and present
|
164
|
+
if @log_output
|
165
|
+
log_data[:stdout_lines] = result.stdout&.split("\n")&.length || 0
|
166
|
+
log_data[:stderr_lines] = result.stderr&.split("\n")&.length || 0
|
167
|
+
log_data[:stdout] = result.stdout if result.stdout && !result.stdout.empty?
|
168
|
+
log_data[:stderr] = result.stderr if result.stderr && !result.stderr.empty?
|
169
|
+
end
|
170
|
+
|
171
|
+
# Log at appropriate level based on success
|
172
|
+
if result.success?
|
173
|
+
@logger.success("Command completed successfully", log_data)
|
174
|
+
else
|
175
|
+
@logger.error("Command completed with errors", log_data)
|
176
|
+
end
|
177
|
+
|
178
|
+
# Log slow commands
|
179
|
+
if @log_performance && duration > 1.0
|
180
|
+
@logger.warn("Slow command detected",
|
181
|
+
command_id: command_id,
|
182
|
+
command: request.command,
|
183
|
+
duration: duration)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
# Log command execution error.
|
188
|
+
#
|
189
|
+
# @param request [Request] command request
|
190
|
+
# @param error [Exception] execution error
|
191
|
+
# @param duration [Float] execution duration
|
192
|
+
# @param command_id [String] unique command identifier
|
193
|
+
def log_command_error(request, error, duration, command_id)
|
194
|
+
@logger.error("Command execution failed", {
|
195
|
+
command_id: command_id,
|
196
|
+
command: request.command,
|
197
|
+
arguments: request.arguments,
|
198
|
+
working_directory: request.directory,
|
199
|
+
error_class: error.class.name,
|
200
|
+
error_message: error.message,
|
201
|
+
duration: duration,
|
202
|
+
backtrace: error.backtrace&.first(5),
|
203
|
+
})
|
204
|
+
end
|
205
|
+
|
206
|
+
# Generate a unique command identifier.
|
207
|
+
#
|
208
|
+
# @return [String] unique command ID
|
209
|
+
def generate_command_id
|
210
|
+
"#{::Process.pid}-#{Time.now.to_f}-#{rand(1000)}"
|
211
|
+
end
|
212
|
+
|
213
|
+
# Get current memory usage (if available).
|
214
|
+
#
|
215
|
+
# @return [String, nil] memory usage string or nil if unavailable
|
216
|
+
def get_memory_usage
|
217
|
+
# Try to get memory usage on different platforms
|
218
|
+
if RUBY_PLATFORM.match?(/mswin|mingw/)
|
219
|
+
# Windows - try to get memory usage
|
220
|
+
begin
|
221
|
+
"Unknown"
|
222
|
+
rescue
|
223
|
+
nil
|
224
|
+
end
|
225
|
+
else
|
226
|
+
# Unix-like systems
|
227
|
+
begin
|
228
|
+
# Try to get memory usage from /proc/self/status
|
229
|
+
if File.exist?("/proc/self/status")
|
230
|
+
status = File.read("/proc/self/status")
|
231
|
+
if match = status.match(/VmRSS:\s+(\d+)\s+kB/)
|
232
|
+
"#{match[1].to_i / 1024}MB"
|
233
|
+
end
|
234
|
+
end
|
235
|
+
rescue
|
236
|
+
nil
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|