makit 0.0.169 → 0.0.171

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 (179) 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 +187 -187
  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/github_actions.rb +202 -202
  84. data/lib/makit/gitlab/pipeline.rb +857 -857
  85. data/lib/makit/gitlab/pipeline_service_impl.rb +1535 -1535
  86. data/lib/makit/gitlab_runner.rb +59 -59
  87. data/lib/makit/humanize.rb +218 -218
  88. data/lib/makit/indexer.rb +47 -47
  89. data/lib/makit/io/filesystem.rb +111 -111
  90. data/lib/makit/io/filesystem_service_impl.rb +337 -337
  91. data/lib/makit/lint.rb +212 -212
  92. data/lib/makit/logging/configuration.rb +309 -309
  93. data/lib/makit/logging/format_registry.rb +84 -84
  94. data/lib/makit/logging/formatters/base.rb +39 -39
  95. data/lib/makit/logging/formatters/console_formatter.rb +140 -140
  96. data/lib/makit/logging/formatters/json_formatter.rb +65 -65
  97. data/lib/makit/logging/formatters/plain_text_formatter.rb +71 -71
  98. data/lib/makit/logging/formatters/text_formatter.rb +64 -64
  99. data/lib/makit/logging/log_request.rb +119 -119
  100. data/lib/makit/logging/logger.rb +199 -199
  101. data/lib/makit/logging/sinks/base.rb +91 -91
  102. data/lib/makit/logging/sinks/console.rb +72 -72
  103. data/lib/makit/logging/sinks/file_sink.rb +92 -92
  104. data/lib/makit/logging/sinks/structured.rb +123 -123
  105. data/lib/makit/logging/sinks/unified_file_sink.rb +296 -296
  106. data/lib/makit/logging.rb +578 -578
  107. data/lib/makit/markdown.rb +75 -75
  108. data/lib/makit/mp/basic_object_mp.rb +17 -17
  109. data/lib/makit/mp/command_mp.rb +13 -13
  110. data/lib/makit/mp/command_request.mp.rb +17 -17
  111. data/lib/makit/mp/project_mp.rb +199 -199
  112. data/lib/makit/mp/string_mp.rb +205 -205
  113. data/lib/makit/nuget.rb +536 -460
  114. data/lib/makit/podman/podman.rb +458 -458
  115. data/lib/makit/podman/podman_service_impl.rb +1081 -1081
  116. data/lib/makit/port.rb +32 -32
  117. data/lib/makit/process.rb +377 -377
  118. data/lib/makit/protoc.rb +112 -112
  119. data/lib/makit/rake/cli.rb +196 -196
  120. data/lib/makit/rake/trace_controller.rb +174 -174
  121. data/lib/makit/rake.rb +81 -81
  122. data/lib/makit/ruby/cli.rb +185 -185
  123. data/lib/makit/ruby.rb +25 -25
  124. data/lib/makit/rubygems.rb +137 -137
  125. data/lib/makit/secrets/azure_key_vault.rb +322 -322
  126. data/lib/makit/secrets/azure_secrets.rb +221 -221
  127. data/lib/makit/secrets/local_secrets.rb +72 -72
  128. data/lib/makit/secrets/secrets_manager.rb +105 -105
  129. data/lib/makit/secrets.rb +96 -96
  130. data/lib/makit/serializer.rb +130 -130
  131. data/lib/makit/services/builder.rb +186 -186
  132. data/lib/makit/services/error_handler.rb +226 -226
  133. data/lib/makit/services/repository_manager.rb +367 -367
  134. data/lib/makit/services/validator.rb +112 -112
  135. data/lib/makit/setup/classlib.rb +101 -101
  136. data/lib/makit/setup/gem.rb +268 -268
  137. data/lib/makit/setup/pages.rb +11 -11
  138. data/lib/makit/setup/razorclasslib.rb +101 -101
  139. data/lib/makit/setup/runner.rb +54 -54
  140. data/lib/makit/setup.rb +5 -5
  141. data/lib/makit/show.rb +110 -110
  142. data/lib/makit/storage.rb +126 -126
  143. data/lib/makit/symbols.rb +175 -175
  144. data/lib/makit/task_info.rb +130 -130
  145. data/lib/makit/tasks/at_exit.rb +15 -15
  146. data/lib/makit/tasks/build.rb +22 -22
  147. data/lib/makit/tasks/bump.rb +7 -7
  148. data/lib/makit/tasks/clean.rb +13 -13
  149. data/lib/makit/tasks/configure.rb +10 -10
  150. data/lib/makit/tasks/format.rb +10 -10
  151. data/lib/makit/tasks/hook_manager.rb +443 -443
  152. data/lib/makit/tasks/info.rb +368 -368
  153. data/lib/makit/tasks/init.rb +49 -49
  154. data/lib/makit/tasks/integrate.rb +60 -60
  155. data/lib/makit/tasks/pull_incoming.rb +13 -13
  156. data/lib/makit/tasks/secrets.rb +7 -7
  157. data/lib/makit/tasks/setup.rb +16 -16
  158. data/lib/makit/tasks/sync.rb +14 -14
  159. data/lib/makit/tasks/tag.rb +27 -27
  160. data/lib/makit/tasks/task_monkey_patch.rb +81 -81
  161. data/lib/makit/tasks/test.rb +22 -22
  162. data/lib/makit/tasks/update.rb +21 -21
  163. data/lib/makit/tasks/version.rb +6 -6
  164. data/lib/makit/tasks.rb +24 -24
  165. data/lib/makit/test_cache.rb +239 -239
  166. data/lib/makit/tree.rb +37 -37
  167. data/lib/makit/v1/configuration/project_service_impl.rb +370 -370
  168. data/lib/makit/v1/git/git_repository_service_impl.rb +295 -295
  169. data/lib/makit/v1/makit.v1_pb.rb +35 -35
  170. data/lib/makit/v1/makit.v1_services_pb.rb +27 -27
  171. data/lib/makit/v1/services/repository_manager_service_impl.rb +572 -572
  172. data/lib/makit/version.rb +661 -661
  173. data/lib/makit/version_util.rb +21 -21
  174. data/lib/makit/wix.rb +95 -95
  175. data/lib/makit/yaml.rb +29 -29
  176. data/lib/makit/zip.rb +17 -17
  177. data/lib/makit copy.rb +44 -44
  178. data/lib/makit.rb +121 -121
  179. metadata +2 -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