makit 0.0.164 → 0.0.166

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