makit 0.0.112 → 0.0.126

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 (147) 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/cli/build_commands.rb +500 -500
  6. data/lib/makit/cli/generators/base_generator.rb +74 -74
  7. data/lib/makit/cli/generators/dotnet_generator.rb +50 -50
  8. data/lib/makit/cli/generators/generator_factory.rb +49 -49
  9. data/lib/makit/cli/generators/node_generator.rb +50 -50
  10. data/lib/makit/cli/generators/ruby_generator.rb +77 -77
  11. data/lib/makit/cli/generators/rust_generator.rb +50 -50
  12. data/lib/makit/cli/generators/templates/dotnet_templates.rb +167 -167
  13. data/lib/makit/cli/generators/templates/node_templates.rb +161 -161
  14. data/lib/makit/cli/generators/templates/ruby/gemfile.rb +26 -26
  15. data/lib/makit/cli/generators/templates/ruby/gemspec.rb +40 -40
  16. data/lib/makit/cli/generators/templates/ruby/main_lib.rb +33 -33
  17. data/lib/makit/cli/generators/templates/ruby/rakefile.rb +35 -35
  18. data/lib/makit/cli/generators/templates/ruby/readme.rb +63 -63
  19. data/lib/makit/cli/generators/templates/ruby/test.rb +39 -39
  20. data/lib/makit/cli/generators/templates/ruby/test_helper.rb +29 -29
  21. data/lib/makit/cli/generators/templates/ruby/version.rb +29 -29
  22. data/lib/makit/cli/generators/templates/rust_templates.rb +128 -128
  23. data/lib/makit/cli/main.rb +62 -62
  24. data/lib/makit/cli/project_commands.rb +868 -868
  25. data/lib/makit/cli/repository_commands.rb +661 -661
  26. data/lib/makit/cli/utility_commands.rb +521 -521
  27. data/lib/makit/commands/factory.rb +359 -359
  28. data/lib/makit/commands/middleware/base.rb +73 -73
  29. data/lib/makit/commands/middleware/cache.rb +248 -248
  30. data/lib/makit/commands/middleware/command_logger.rb +311 -320
  31. data/lib/makit/commands/middleware/validator.rb +269 -269
  32. data/lib/makit/commands/request.rb +316 -254
  33. data/lib/makit/commands/result.rb +323 -323
  34. data/lib/makit/commands/runner.rb +368 -337
  35. data/lib/makit/commands/strategies/base.rb +171 -160
  36. data/lib/makit/commands/strategies/synchronous.rb +139 -134
  37. data/lib/makit/commands.rb +50 -51
  38. data/lib/makit/configuration/gitlab_helper.rb +58 -60
  39. data/lib/makit/configuration/project.rb +167 -127
  40. data/lib/makit/configuration/rakefile_helper.rb +43 -43
  41. data/lib/makit/configuration/step.rb +34 -34
  42. data/lib/makit/configuration.rb +14 -14
  43. data/lib/makit/content/default_gitignore.rb +7 -7
  44. data/lib/makit/content/default_gitignore.txt +226 -0
  45. data/lib/makit/content/default_rakefile.rb +13 -13
  46. data/lib/makit/content/gem_rakefile.rb +16 -16
  47. data/lib/makit/context.rb +1 -1
  48. data/lib/makit/data.rb +49 -49
  49. data/lib/makit/directories.rb +140 -141
  50. data/lib/makit/directory.rb +262 -262
  51. data/lib/makit/docs/files.rb +89 -89
  52. data/lib/makit/docs/rake.rb +102 -102
  53. data/lib/makit/dotnet/cli.rb +69 -65
  54. data/lib/makit/dotnet/project.rb +217 -153
  55. data/lib/makit/dotnet/solution.rb +38 -38
  56. data/lib/makit/dotnet/solution_classlib.rb +239 -239
  57. data/lib/makit/dotnet/solution_console.rb +264 -264
  58. data/lib/makit/dotnet/solution_maui.rb +354 -354
  59. data/lib/makit/dotnet/solution_wasm.rb +275 -275
  60. data/lib/makit/dotnet/solution_wpf.rb +304 -304
  61. data/lib/makit/dotnet.rb +102 -102
  62. data/lib/makit/email.rb +90 -90
  63. data/lib/makit/environment.rb +142 -142
  64. data/lib/makit/examples/runner.rb +370 -370
  65. data/lib/makit/exceptions.rb +45 -45
  66. data/lib/makit/fileinfo.rb +24 -24
  67. data/lib/makit/files.rb +43 -43
  68. data/lib/makit/gems.rb +40 -40
  69. data/lib/makit/git/cli.rb +54 -54
  70. data/lib/makit/git/repository.rb +90 -90
  71. data/lib/makit/git.rb +98 -98
  72. data/lib/makit/gitlab_runner.rb +59 -59
  73. data/lib/makit/humanize.rb +137 -137
  74. data/lib/makit/indexer.rb +47 -47
  75. data/lib/makit/logging/configuration.rb +308 -305
  76. data/lib/makit/logging/format_registry.rb +84 -84
  77. data/lib/makit/logging/formatters/base.rb +39 -39
  78. data/lib/makit/logging/formatters/console_formatter.rb +140 -140
  79. data/lib/makit/logging/formatters/json_formatter.rb +65 -65
  80. data/lib/makit/logging/formatters/plain_text_formatter.rb +71 -71
  81. data/lib/makit/logging/formatters/text_formatter.rb +64 -64
  82. data/lib/makit/logging/log_request.rb +119 -115
  83. data/lib/makit/logging/logger.rb +199 -163
  84. data/lib/makit/logging/sinks/base.rb +91 -91
  85. data/lib/makit/logging/sinks/console.rb +72 -72
  86. data/lib/makit/logging/sinks/file_sink.rb +92 -92
  87. data/lib/makit/logging/sinks/structured.rb +123 -129
  88. data/lib/makit/logging/sinks/unified_file_sink.rb +296 -303
  89. data/lib/makit/logging.rb +565 -530
  90. data/lib/makit/markdown.rb +75 -75
  91. data/lib/makit/mp/basic_object_mp.rb +17 -17
  92. data/lib/makit/mp/command_mp.rb +13 -13
  93. data/lib/makit/mp/command_request.mp.rb +17 -17
  94. data/lib/makit/mp/project_mp.rb +199 -199
  95. data/lib/makit/mp/string_mp.rb +191 -193
  96. data/lib/makit/nuget.rb +74 -74
  97. data/lib/makit/port.rb +32 -32
  98. data/lib/makit/process.rb +163 -163
  99. data/lib/makit/protoc.rb +107 -107
  100. data/lib/makit/rake/cli.rb +196 -196
  101. data/lib/makit/rake.rb +25 -25
  102. data/lib/makit/ruby/cli.rb +185 -185
  103. data/lib/makit/ruby.rb +25 -25
  104. data/lib/makit/secrets.rb +51 -51
  105. data/lib/makit/serializer.rb +130 -130
  106. data/lib/makit/services/builder.rb +186 -186
  107. data/lib/makit/services/error_handler.rb +226 -226
  108. data/lib/makit/services/repository_manager.rb +231 -229
  109. data/lib/makit/services/validator.rb +112 -112
  110. data/lib/makit/setup/classlib.rb +90 -53
  111. data/lib/makit/setup/gem.rb +268 -263
  112. data/lib/makit/setup/razorclasslib.rb +91 -0
  113. data/lib/makit/setup/runner.rb +54 -45
  114. data/lib/makit/setup.rb +5 -5
  115. data/lib/makit/show.rb +110 -110
  116. data/lib/makit/storage.rb +126 -126
  117. data/lib/makit/symbols.rb +170 -170
  118. data/lib/makit/task_info.rb +128 -128
  119. data/lib/makit/tasks/at_exit.rb +15 -13
  120. data/lib/makit/tasks/build.rb +22 -19
  121. data/lib/makit/tasks/clean.rb +13 -11
  122. data/lib/makit/tasks/configure.rb +10 -0
  123. data/lib/makit/tasks/format.rb +10 -0
  124. data/lib/makit/tasks/hook_manager.rb +391 -393
  125. data/lib/makit/tasks/init.rb +49 -47
  126. data/lib/makit/tasks/integrate.rb +29 -17
  127. data/lib/makit/tasks/pull_incoming.rb +13 -11
  128. data/lib/makit/tasks/setup.rb +13 -6
  129. data/lib/makit/tasks/sync.rb +17 -12
  130. data/lib/makit/tasks/tag.rb +16 -15
  131. data/lib/makit/tasks/task_monkey_patch.rb +81 -79
  132. data/lib/makit/tasks/test.rb +22 -0
  133. data/lib/makit/tasks/update.rb +18 -0
  134. data/lib/makit/tasks.rb +20 -15
  135. data/lib/makit/test_cache.rb +239 -239
  136. data/lib/makit/tree.rb +37 -37
  137. data/lib/makit/v1/makit.v1_pb.rb +35 -34
  138. data/lib/makit/v1/makit.v1_services_pb.rb +27 -27
  139. data/lib/makit/version.rb +5 -5
  140. data/lib/makit/version_util.rb +21 -21
  141. data/lib/makit/wix.rb +95 -95
  142. data/lib/makit/yaml.rb +29 -29
  143. data/lib/makit/zip.rb +17 -17
  144. data/lib/makit copy.rb +44 -44
  145. data/lib/makit.rb +39 -40
  146. metadata +69 -7
  147. data/lib/makit/commands/middleware/unified_logger.rb +0 -243
@@ -1,320 +1,311 @@
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
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
+ # Log slow commands
234
+ if duration > 5.0
235
+ @logger.warn("Slow command detected",
236
+ command_id: command_id,
237
+ command: request.command,
238
+ duration: duration,
239
+ threshold: "5.0s")
240
+ end
241
+
242
+ # Log commands with large output
243
+ output_size = calculate_output_size(result)
244
+ if output_size > 100_000 # 100KB
245
+ @logger.warn("Command with large output detected",
246
+ command_id: command_id,
247
+ command: request.command,
248
+ output_size: "#{output_size / 1024}KB",
249
+ threshold: "100KB")
250
+ end
251
+
252
+ # Log commands with high exit codes (potential errors)
253
+ return unless result.exit_code.positive?
254
+
255
+ @logger.debug("Command completed with non-zero exit code",
256
+ command_id: command_id,
257
+ command: request.command,
258
+ exit_code: result.exit_code,
259
+ success: result.success?)
260
+ end
261
+
262
+ # Calculate total output size (stdout + stderr).
263
+ #
264
+ # @param result [Result] execution result
265
+ # @return [Integer] total output size in bytes
266
+ def calculate_output_size(result)
267
+ size = 0
268
+ size += result.stdout&.bytesize || 0
269
+ size += result.stderr&.bytesize || 0
270
+ size
271
+ end
272
+
273
+ # Generate a unique command identifier.
274
+ #
275
+ # @return [String] unique command ID
276
+ def generate_command_id
277
+ "#{::Process.pid}-#{Time.now.to_f}-#{rand(1000)}"
278
+ end
279
+
280
+ # Get current memory usage (if available).
281
+ #
282
+ # @return [String, nil] memory usage string or nil if unavailable
283
+ def get_memory_usage
284
+ # Try to get memory usage on different platforms
285
+ if RUBY_PLATFORM.match?(/mswin|mingw/)
286
+ # Windows - try to get memory usage
287
+ begin
288
+ # This is a simplified approach for Windows
289
+ "Unknown"
290
+ rescue StandardError
291
+ nil
292
+ end
293
+ else
294
+ # Unix-like systems
295
+ begin
296
+ # Try to get memory usage from /proc/self/status
297
+ if File.exist?("/proc/self/status")
298
+ status = File.read("/proc/self/status")
299
+ if (match = status.match(/VmRSS:\s+(\d+)\s+kB/))
300
+ "#{match[1].to_i / 1024}MB"
301
+ end
302
+ end
303
+ rescue StandardError
304
+ nil
305
+ end
306
+ end
307
+ end
308
+ end
309
+ end
310
+ end
311
+ end