makit 0.0.144 → 0.0.145

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 (165) 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/cli/base.rb +17 -0
  7. data/lib/makit/cli/build_commands.rb +500 -500
  8. data/lib/makit/cli/generators/base_generator.rb +74 -74
  9. data/lib/makit/cli/generators/dotnet_generator.rb +50 -50
  10. data/lib/makit/cli/generators/generator_factory.rb +49 -49
  11. data/lib/makit/cli/generators/node_generator.rb +50 -50
  12. data/lib/makit/cli/generators/ruby_generator.rb +77 -77
  13. data/lib/makit/cli/generators/rust_generator.rb +50 -50
  14. data/lib/makit/cli/generators/templates/dotnet_templates.rb +167 -167
  15. data/lib/makit/cli/generators/templates/node_templates.rb +161 -161
  16. data/lib/makit/cli/generators/templates/ruby/gemfile.rb +26 -26
  17. data/lib/makit/cli/generators/templates/ruby/gemspec.rb +41 -40
  18. data/lib/makit/cli/generators/templates/ruby/main_lib.rb +33 -33
  19. data/lib/makit/cli/generators/templates/ruby/rakefile.rb +35 -35
  20. data/lib/makit/cli/generators/templates/ruby/readme.rb +63 -63
  21. data/lib/makit/cli/generators/templates/ruby/test.rb +39 -39
  22. data/lib/makit/cli/generators/templates/ruby/test_helper.rb +29 -29
  23. data/lib/makit/cli/generators/templates/ruby/version.rb +29 -29
  24. data/lib/makit/cli/generators/templates/rust_templates.rb +128 -128
  25. data/lib/makit/cli/main.rb +78 -69
  26. data/lib/makit/cli/pipeline_commands.rb +311 -0
  27. data/lib/makit/cli/project_commands.rb +868 -868
  28. data/lib/makit/cli/repository_commands.rb +661 -661
  29. data/lib/makit/cli/strategy_commands.rb +207 -212
  30. data/lib/makit/cli/utility_commands.rb +521 -521
  31. data/lib/makit/commands/factory.rb +359 -359
  32. data/lib/makit/commands/middleware/base.rb +73 -73
  33. data/lib/makit/commands/middleware/cache.rb +248 -248
  34. data/lib/makit/commands/middleware/command_logger.rb +312 -312
  35. data/lib/makit/commands/middleware/validator.rb +269 -269
  36. data/lib/makit/commands/request.rb +316 -316
  37. data/lib/makit/commands/result.rb +323 -323
  38. data/lib/makit/commands/runner.rb +386 -386
  39. data/lib/makit/commands/strategies/base.rb +171 -171
  40. data/lib/makit/commands/strategies/child_process.rb +162 -162
  41. data/lib/makit/commands/strategies/factory.rb +136 -136
  42. data/lib/makit/commands/strategies/synchronous.rb +139 -139
  43. data/lib/makit/commands.rb +50 -50
  44. data/lib/makit/configuration/dotnet_project.rb +48 -48
  45. data/lib/makit/configuration/gitlab_helper.rb +61 -58
  46. data/lib/makit/configuration/project.rb +446 -168
  47. data/lib/makit/configuration/rakefile_helper.rb +43 -43
  48. data/lib/makit/configuration/step.rb +34 -34
  49. data/lib/makit/configuration/timeout.rb +74 -74
  50. data/lib/makit/configuration.rb +21 -16
  51. data/lib/makit/content/default_gitignore.rb +7 -7
  52. data/lib/makit/content/default_gitignore.txt +225 -225
  53. data/lib/makit/content/default_rakefile.rb +13 -13
  54. data/lib/makit/content/gem_rakefile.rb +16 -16
  55. data/lib/makit/context.rb +1 -1
  56. data/lib/makit/data.rb +49 -49
  57. data/lib/makit/directories.rb +140 -140
  58. data/lib/makit/directory.rb +262 -262
  59. data/lib/makit/docs/files.rb +89 -89
  60. data/lib/makit/docs/rake.rb +102 -102
  61. data/lib/makit/dotnet/cli.rb +69 -69
  62. data/lib/makit/dotnet/project.rb +217 -217
  63. data/lib/makit/dotnet/solution.rb +38 -38
  64. data/lib/makit/dotnet/solution_classlib.rb +239 -239
  65. data/lib/makit/dotnet/solution_console.rb +264 -264
  66. data/lib/makit/dotnet/solution_maui.rb +354 -354
  67. data/lib/makit/dotnet/solution_wasm.rb +275 -275
  68. data/lib/makit/dotnet/solution_wpf.rb +304 -304
  69. data/lib/makit/dotnet.rb +102 -102
  70. data/lib/makit/email.rb +90 -90
  71. data/lib/makit/environment.rb +142 -142
  72. data/lib/makit/examples/runner.rb +370 -370
  73. data/lib/makit/exceptions.rb +45 -45
  74. data/lib/makit/fileinfo.rb +32 -24
  75. data/lib/makit/files.rb +43 -43
  76. data/lib/makit/gems.rb +40 -40
  77. data/lib/makit/git/cli.rb +54 -54
  78. data/lib/makit/git/repository.rb +266 -90
  79. data/lib/makit/git.rb +104 -98
  80. data/lib/makit/gitlab/pipeline.rb +857 -0
  81. data/lib/makit/gitlab/pipeline_service_impl.rb +1536 -0
  82. data/lib/makit/gitlab_runner.rb +59 -59
  83. data/lib/makit/humanize.rb +218 -137
  84. data/lib/makit/indexer.rb +47 -47
  85. data/lib/makit/io/filesystem.rb +111 -0
  86. data/lib/makit/io/filesystem_service_impl.rb +337 -0
  87. data/lib/makit/logging/configuration.rb +308 -308
  88. data/lib/makit/logging/format_registry.rb +84 -84
  89. data/lib/makit/logging/formatters/base.rb +39 -39
  90. data/lib/makit/logging/formatters/console_formatter.rb +140 -140
  91. data/lib/makit/logging/formatters/json_formatter.rb +65 -65
  92. data/lib/makit/logging/formatters/plain_text_formatter.rb +71 -71
  93. data/lib/makit/logging/formatters/text_formatter.rb +64 -64
  94. data/lib/makit/logging/log_request.rb +119 -119
  95. data/lib/makit/logging/logger.rb +199 -199
  96. data/lib/makit/logging/sinks/base.rb +91 -91
  97. data/lib/makit/logging/sinks/console.rb +72 -72
  98. data/lib/makit/logging/sinks/file_sink.rb +92 -92
  99. data/lib/makit/logging/sinks/structured.rb +123 -123
  100. data/lib/makit/logging/sinks/unified_file_sink.rb +296 -296
  101. data/lib/makit/logging.rb +565 -565
  102. data/lib/makit/markdown.rb +75 -75
  103. data/lib/makit/mp/basic_object_mp.rb +17 -17
  104. data/lib/makit/mp/command_mp.rb +13 -13
  105. data/lib/makit/mp/command_request.mp.rb +17 -17
  106. data/lib/makit/mp/project_mp.rb +199 -199
  107. data/lib/makit/mp/string_mp.rb +205 -199
  108. data/lib/makit/nuget.rb +74 -74
  109. data/lib/makit/podman/podman.rb +458 -0
  110. data/lib/makit/podman/podman_service_impl.rb +1081 -0
  111. data/lib/makit/port.rb +32 -32
  112. data/lib/makit/process.rb +377 -377
  113. data/lib/makit/protoc.rb +112 -107
  114. data/lib/makit/rake/cli.rb +196 -196
  115. data/lib/makit/rake/trace_controller.rb +174 -174
  116. data/lib/makit/rake.rb +81 -81
  117. data/lib/makit/ruby/cli.rb +185 -185
  118. data/lib/makit/ruby.rb +25 -25
  119. data/lib/makit/secrets.rb +51 -51
  120. data/lib/makit/serializer.rb +130 -130
  121. data/lib/makit/services/builder.rb +186 -186
  122. data/lib/makit/services/error_handler.rb +226 -226
  123. data/lib/makit/services/repository_manager.rb +367 -231
  124. data/lib/makit/services/validator.rb +112 -112
  125. data/lib/makit/setup/classlib.rb +101 -101
  126. data/lib/makit/setup/gem.rb +268 -268
  127. data/lib/makit/setup/pages.rb +11 -11
  128. data/lib/makit/setup/razorclasslib.rb +101 -101
  129. data/lib/makit/setup/runner.rb +54 -54
  130. data/lib/makit/setup.rb +5 -5
  131. data/lib/makit/show.rb +110 -110
  132. data/lib/makit/storage.rb +126 -126
  133. data/lib/makit/symbols.rb +175 -170
  134. data/lib/makit/task_info.rb +130 -130
  135. data/lib/makit/tasks/at_exit.rb +15 -15
  136. data/lib/makit/tasks/build.rb +22 -22
  137. data/lib/makit/tasks/clean.rb +13 -13
  138. data/lib/makit/tasks/configure.rb +10 -10
  139. data/lib/makit/tasks/format.rb +10 -10
  140. data/lib/makit/tasks/hook_manager.rb +443 -443
  141. data/lib/makit/tasks/init.rb +49 -49
  142. data/lib/makit/tasks/integrate.rb +29 -29
  143. data/lib/makit/tasks/pull_incoming.rb +13 -13
  144. data/lib/makit/tasks/setup.rb +16 -16
  145. data/lib/makit/tasks/sync.rb +17 -17
  146. data/lib/makit/tasks/tag.rb +16 -16
  147. data/lib/makit/tasks/task_monkey_patch.rb +81 -81
  148. data/lib/makit/tasks/test.rb +22 -22
  149. data/lib/makit/tasks/update.rb +18 -18
  150. data/lib/makit/tasks.rb +20 -20
  151. data/lib/makit/test_cache.rb +239 -239
  152. data/lib/makit/tree.rb +37 -37
  153. data/lib/makit/v1/configuration/project_service_impl.rb +371 -0
  154. data/lib/makit/v1/git/git_repository_service_impl.rb +295 -0
  155. data/lib/makit/v1/makit.v1_pb.rb +35 -35
  156. data/lib/makit/v1/makit.v1_services_pb.rb +27 -27
  157. data/lib/makit/v1/services/repository_manager_service_impl.rb +572 -0
  158. data/lib/makit/version.rb +100 -100
  159. data/lib/makit/version_util.rb +21 -21
  160. data/lib/makit/wix.rb +95 -95
  161. data/lib/makit/yaml.rb +29 -29
  162. data/lib/makit/zip.rb +17 -17
  163. data/lib/makit copy.rb +44 -44
  164. data/lib/makit.rb +111 -43
  165. metadata +61 -36
@@ -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