makit 0.0.99 → 0.0.112

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.
Files changed (152) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +41 -0
  3. data/exe/makit +5 -0
  4. data/lib/makit/apache.rb +28 -32
  5. data/lib/makit/cli/build_commands.rb +500 -0
  6. data/lib/makit/cli/generators/base_generator.rb +74 -0
  7. data/lib/makit/cli/generators/dotnet_generator.rb +50 -0
  8. data/lib/makit/cli/generators/generator_factory.rb +49 -0
  9. data/lib/makit/cli/generators/node_generator.rb +50 -0
  10. data/lib/makit/cli/generators/ruby_generator.rb +77 -0
  11. data/lib/makit/cli/generators/rust_generator.rb +50 -0
  12. data/lib/makit/cli/generators/templates/dotnet_templates.rb +167 -0
  13. data/lib/makit/cli/generators/templates/node_templates.rb +161 -0
  14. data/lib/makit/cli/generators/templates/ruby/gemfile.rb +26 -0
  15. data/lib/makit/cli/generators/templates/ruby/gemspec.rb +40 -0
  16. data/lib/makit/cli/generators/templates/ruby/main_lib.rb +33 -0
  17. data/lib/makit/cli/generators/templates/ruby/rakefile.rb +35 -0
  18. data/lib/makit/cli/generators/templates/ruby/readme.rb +63 -0
  19. data/lib/makit/cli/generators/templates/ruby/test.rb +39 -0
  20. data/lib/makit/cli/generators/templates/ruby/test_helper.rb +29 -0
  21. data/lib/makit/cli/generators/templates/ruby/version.rb +29 -0
  22. data/lib/makit/cli/generators/templates/rust_templates.rb +128 -0
  23. data/lib/makit/cli/main.rb +62 -33
  24. data/lib/makit/cli/project_commands.rb +868 -0
  25. data/lib/makit/cli/repository_commands.rb +661 -0
  26. data/lib/makit/cli/utility_commands.rb +521 -0
  27. data/lib/makit/commands/factory.rb +359 -0
  28. data/lib/makit/commands/middleware/base.rb +73 -0
  29. data/lib/makit/commands/middleware/cache.rb +248 -0
  30. data/lib/makit/commands/middleware/command_logger.rb +320 -0
  31. data/lib/makit/commands/middleware/unified_logger.rb +243 -0
  32. data/lib/makit/commands/middleware/validator.rb +269 -0
  33. data/lib/makit/commands/request.rb +254 -0
  34. data/lib/makit/commands/result.rb +323 -0
  35. data/lib/makit/commands/runner.rb +337 -0
  36. data/lib/makit/commands/strategies/base.rb +160 -0
  37. data/lib/makit/commands/strategies/synchronous.rb +134 -0
  38. data/lib/makit/commands.rb +51 -21
  39. data/lib/makit/configuration/gitlab_helper.rb +60 -0
  40. data/lib/makit/configuration/project.rb +127 -0
  41. data/lib/makit/configuration/rakefile_helper.rb +43 -0
  42. data/lib/makit/configuration/step.rb +34 -0
  43. data/lib/makit/configuration.rb +14 -0
  44. data/lib/makit/content/default_gitignore.rb +7 -5
  45. data/lib/makit/content/default_rakefile.rb +13 -11
  46. data/lib/makit/content/gem_rakefile.rb +16 -14
  47. data/lib/makit/context.rb +1 -0
  48. data/lib/makit/data.rb +49 -50
  49. data/lib/makit/directories.rb +141 -145
  50. data/lib/makit/directory.rb +262 -276
  51. data/lib/makit/docs/files.rb +89 -94
  52. data/lib/makit/docs/rake.rb +102 -106
  53. data/lib/makit/dotnet/cli.rb +65 -0
  54. data/lib/makit/dotnet/project.rb +153 -0
  55. data/lib/makit/dotnet/solution.rb +38 -0
  56. data/lib/makit/dotnet/solution_classlib.rb +239 -0
  57. data/lib/makit/dotnet/solution_console.rb +264 -0
  58. data/lib/makit/dotnet/solution_maui.rb +354 -0
  59. data/lib/makit/dotnet/solution_wasm.rb +275 -0
  60. data/lib/makit/dotnet/solution_wpf.rb +304 -0
  61. data/lib/makit/dotnet.rb +102 -219
  62. data/lib/makit/email.rb +90 -61
  63. data/lib/makit/environment.rb +142 -139
  64. data/lib/makit/examples/runner.rb +370 -0
  65. data/lib/makit/exceptions.rb +45 -0
  66. data/lib/makit/fileinfo.rb +24 -26
  67. data/lib/makit/files.rb +43 -47
  68. data/lib/makit/gems.rb +29 -28
  69. data/lib/makit/git/cli.rb +54 -0
  70. data/lib/makit/git/repository.rb +90 -0
  71. data/lib/makit/git.rb +98 -145
  72. data/lib/makit/gitlab_runner.rb +59 -60
  73. data/lib/makit/humanize.rb +137 -129
  74. data/lib/makit/indexer.rb +47 -56
  75. data/lib/makit/logging/configuration.rb +305 -0
  76. data/lib/makit/logging/format_registry.rb +84 -0
  77. data/lib/makit/logging/formatters/base.rb +39 -0
  78. data/lib/makit/logging/formatters/console_formatter.rb +140 -0
  79. data/lib/makit/logging/formatters/json_formatter.rb +65 -0
  80. data/lib/makit/logging/formatters/plain_text_formatter.rb +71 -0
  81. data/lib/makit/logging/formatters/text_formatter.rb +64 -0
  82. data/lib/makit/logging/log_request.rb +115 -0
  83. data/lib/makit/logging/logger.rb +163 -0
  84. data/lib/makit/logging/sinks/base.rb +91 -0
  85. data/lib/makit/logging/sinks/console.rb +72 -0
  86. data/lib/makit/logging/sinks/file_sink.rb +92 -0
  87. data/lib/makit/logging/sinks/structured.rb +129 -0
  88. data/lib/makit/logging/sinks/unified_file_sink.rb +303 -0
  89. data/lib/makit/logging.rb +530 -106
  90. data/lib/makit/markdown.rb +75 -75
  91. data/lib/makit/mp/basic_object_mp.rb +17 -16
  92. data/lib/makit/mp/command_mp.rb +13 -13
  93. data/lib/makit/mp/command_request.mp.rb +17 -16
  94. data/lib/makit/mp/project_mp.rb +199 -210
  95. data/lib/makit/mp/string_mp.rb +193 -176
  96. data/lib/makit/nuget.rb +74 -72
  97. data/lib/makit/port.rb +32 -34
  98. data/lib/makit/process.rb +163 -65
  99. data/lib/makit/protoc.rb +107 -104
  100. data/lib/makit/rake/cli.rb +196 -0
  101. data/lib/makit/rake.rb +25 -25
  102. data/lib/makit/ruby/cli.rb +185 -0
  103. data/lib/makit/ruby.rb +25 -0
  104. data/lib/makit/secrets.rb +51 -51
  105. data/lib/makit/serializer.rb +130 -115
  106. data/lib/makit/services/builder.rb +186 -0
  107. data/lib/makit/services/error_handler.rb +226 -0
  108. data/lib/makit/services/repository_manager.rb +229 -0
  109. data/lib/makit/services/validator.rb +112 -0
  110. data/lib/makit/setup/classlib.rb +53 -0
  111. data/lib/makit/setup/gem.rb +263 -0
  112. data/lib/makit/setup/runner.rb +45 -0
  113. data/lib/makit/setup.rb +5 -0
  114. data/lib/makit/show.rb +110 -110
  115. data/lib/makit/storage.rb +126 -131
  116. data/lib/makit/symbols.rb +170 -149
  117. data/lib/makit/task_info.rb +128 -86
  118. data/lib/makit/tasks/at_exit.rb +13 -0
  119. data/lib/makit/tasks/build.rb +19 -0
  120. data/lib/makit/tasks/clean.rb +11 -0
  121. data/lib/makit/tasks/hook_manager.rb +393 -0
  122. data/lib/makit/tasks/init.rb +47 -0
  123. data/lib/makit/tasks/integrate.rb +17 -0
  124. data/lib/makit/tasks/pull_incoming.rb +11 -0
  125. data/lib/makit/tasks/setup.rb +6 -0
  126. data/lib/makit/tasks/sync.rb +12 -0
  127. data/lib/makit/tasks/tag.rb +15 -0
  128. data/lib/makit/tasks/task_monkey_patch.rb +79 -0
  129. data/lib/makit/tasks.rb +15 -150
  130. data/lib/makit/test_cache.rb +239 -0
  131. data/lib/makit/tree.rb +37 -37
  132. data/lib/makit/v1/makit.v1_pb.rb +3 -4
  133. data/lib/makit/v1/makit.v1_services_pb.rb +27 -25
  134. data/lib/makit/version.rb +5 -61
  135. data/lib/makit/version_util.rb +21 -0
  136. data/lib/makit/wix.rb +95 -95
  137. data/lib/makit/yaml.rb +29 -17
  138. data/lib/makit/zip.rb +17 -17
  139. data/lib/makit copy.rb +44 -0
  140. data/lib/makit.rb +40 -267
  141. metadata +117 -110
  142. data/lib/makit/cli/clean.rb +0 -14
  143. data/lib/makit/cli/clone.rb +0 -59
  144. data/lib/makit/cli/init.rb +0 -38
  145. data/lib/makit/cli/make.rb +0 -54
  146. data/lib/makit/cli/new.rb +0 -37
  147. data/lib/makit/cli/nuget_cache.rb +0 -38
  148. data/lib/makit/cli/pull.rb +0 -31
  149. data/lib/makit/cli/setup.rb +0 -71
  150. data/lib/makit/cli/work.rb +0 -21
  151. data/lib/makit/command_runner.rb +0 -404
  152. data/lib/makit/content/default_gitignore.txt +0 -222
@@ -0,0 +1,320 @@
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.debug("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 detailed information at debug level
166
+ @logger.debug("Command completed successfully", log_data) if result.success?
167
+ @logger.debug("Command completed with errors", log_data) unless result.success?
168
+
169
+ # Log performance warnings
170
+ log_performance_warnings(request, result, duration, command_id) if @log_performance
171
+ end
172
+
173
+ # Log command output (stdout/stderr) with line limits.
174
+ #
175
+ # @param request [Request] command request
176
+ # @param result [Result] execution result
177
+ # @param command_id [String] unique command identifier
178
+ def log_command_output(request, result, command_id)
179
+ # Log stdout if enabled and present
180
+ if @log_stdout && result.stdout && !result.stdout.empty?
181
+ output_lines = result.stdout.split("\n")
182
+ truncated = output_lines.length > @max_output_lines
183
+
184
+ log_data = {
185
+ command_id: command_id,
186
+ command: request.command,
187
+ output: truncated ? output_lines.first(@max_output_lines).join("\n") : result.stdout,
188
+ total_lines: output_lines.length,
189
+ truncated: truncated,
190
+ }
191
+
192
+ @logger.debug("Command stdout", log_data)
193
+ end
194
+
195
+ # Log stderr if enabled and present
196
+ if @log_stderr && result.stderr && !result.stderr.empty?
197
+ output_lines = result.stderr.split("\n")
198
+ truncated = output_lines.length > @max_output_lines
199
+
200
+ log_data = {
201
+ command_id: command_id,
202
+ command: request.command,
203
+ output: truncated ? output_lines.first(@max_output_lines).join("\n") : result.stderr,
204
+ total_lines: output_lines.length,
205
+ truncated: truncated,
206
+ }
207
+
208
+ @logger.warn("Command stderr", log_data)
209
+ end
210
+ end
211
+
212
+ # Log command execution error with full context.
213
+ #
214
+ # @param request [Request] command request
215
+ # @param error [Exception] execution error
216
+ # @param duration [Float] execution duration
217
+ # @param command_id [String] unique command identifier
218
+ def log_command_error(request, error, duration, command_id)
219
+ log_data = {
220
+ command_id: command_id,
221
+ command: request.command,
222
+ arguments: request.arguments,
223
+ working_directory: request.directory,
224
+ environment: request.environment&.keys || [],
225
+ error_class: error.class.name,
226
+ error_message: error.message,
227
+ duration: duration,
228
+ backtrace: error.backtrace&.first(10),
229
+ timestamp: Time.now.iso8601,
230
+ }
231
+
232
+ @logger.error("Command execution failed", log_data)
233
+ end
234
+
235
+ # Log performance warnings for slow or resource-intensive commands.
236
+ #
237
+ # @param request [Request] command request
238
+ # @param result [Result] execution result
239
+ # @param duration [Float] execution duration
240
+ # @param command_id [String] unique command identifier
241
+ def log_performance_warnings(request, result, duration, command_id)
242
+ # Log slow commands
243
+ if duration > 5.0
244
+ @logger.warn("Slow command detected",
245
+ command_id: command_id,
246
+ command: request.command,
247
+ duration: duration,
248
+ threshold: "5.0s")
249
+ end
250
+
251
+ # Log commands with large output
252
+ output_size = calculate_output_size(result)
253
+ if output_size > 100_000 # 100KB
254
+ @logger.warn("Command with large output detected",
255
+ command_id: command_id,
256
+ command: request.command,
257
+ output_size: "#{output_size / 1024}KB",
258
+ threshold: "100KB")
259
+ end
260
+
261
+ # Log commands with high exit codes (potential errors)
262
+ if result.exit_code > 0
263
+ @logger.debug("Command completed with non-zero exit code",
264
+ command_id: command_id,
265
+ command: request.command,
266
+ exit_code: result.exit_code,
267
+ success: result.success?)
268
+ end
269
+ end
270
+
271
+ # Calculate total output size (stdout + stderr).
272
+ #
273
+ # @param result [Result] execution result
274
+ # @return [Integer] total output size in bytes
275
+ def calculate_output_size(result)
276
+ size = 0
277
+ size += result.stdout&.bytesize || 0
278
+ size += result.stderr&.bytesize || 0
279
+ size
280
+ end
281
+
282
+ # Generate a unique command identifier.
283
+ #
284
+ # @return [String] unique command ID
285
+ def generate_command_id
286
+ "#{::Process.pid}-#{Time.now.to_f}-#{rand(1000)}"
287
+ end
288
+
289
+ # Get current memory usage (if available).
290
+ #
291
+ # @return [String, nil] memory usage string or nil if unavailable
292
+ def get_memory_usage
293
+ # Try to get memory usage on different platforms
294
+ if RUBY_PLATFORM.match?(/mswin|mingw/)
295
+ # Windows - try to get memory usage
296
+ begin
297
+ # This is a simplified approach for Windows
298
+ "Unknown"
299
+ rescue
300
+ nil
301
+ end
302
+ else
303
+ # Unix-like systems
304
+ begin
305
+ # Try to get memory usage from /proc/self/status
306
+ if File.exist?("/proc/self/status")
307
+ status = File.read("/proc/self/status")
308
+ if match = status.match(/VmRSS:\s+(\d+)\s+kB/)
309
+ "#{match[1].to_i / 1024}MB"
310
+ end
311
+ end
312
+ rescue
313
+ nil
314
+ end
315
+ end
316
+ end
317
+ end
318
+ end
319
+ end
320
+ 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