makit 0.0.98 → 0.0.111

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 (148) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +41 -0
  3. data/exe/makit +5 -0
  4. data/lib/makit/apache.rb +7 -11
  5. data/lib/makit/cli/build_commands.rb +500 -0
  6. data/lib/makit/cli/generators/base_generator.rb +74 -0
  7. data/lib/makit/cli/generators/dotnet_generator.rb +50 -0
  8. data/lib/makit/cli/generators/generator_factory.rb +49 -0
  9. data/lib/makit/cli/generators/node_generator.rb +50 -0
  10. data/lib/makit/cli/generators/ruby_generator.rb +77 -0
  11. data/lib/makit/cli/generators/rust_generator.rb +50 -0
  12. data/lib/makit/cli/generators/templates/dotnet_templates.rb +167 -0
  13. data/lib/makit/cli/generators/templates/node_templates.rb +161 -0
  14. data/lib/makit/cli/generators/templates/ruby/gemfile.rb +26 -0
  15. data/lib/makit/cli/generators/templates/ruby/gemspec.rb +40 -0
  16. data/lib/makit/cli/generators/templates/ruby/main_lib.rb +33 -0
  17. data/lib/makit/cli/generators/templates/ruby/rakefile.rb +35 -0
  18. data/lib/makit/cli/generators/templates/ruby/readme.rb +63 -0
  19. data/lib/makit/cli/generators/templates/ruby/test.rb +39 -0
  20. data/lib/makit/cli/generators/templates/ruby/test_helper.rb +29 -0
  21. data/lib/makit/cli/generators/templates/ruby/version.rb +29 -0
  22. data/lib/makit/cli/generators/templates/rust_templates.rb +128 -0
  23. data/lib/makit/cli/main.rb +48 -19
  24. data/lib/makit/cli/project_commands.rb +868 -0
  25. data/lib/makit/cli/repository_commands.rb +661 -0
  26. data/lib/makit/cli/utility_commands.rb +521 -0
  27. data/lib/makit/command_runner.rb +187 -128
  28. data/lib/makit/commands/compatibility.rb +365 -0
  29. data/lib/makit/commands/factory.rb +359 -0
  30. data/lib/makit/commands/middleware/base.rb +73 -0
  31. data/lib/makit/commands/middleware/cache.rb +248 -0
  32. data/lib/makit/commands/middleware/command_logger.rb +323 -0
  33. data/lib/makit/commands/middleware/unified_logger.rb +243 -0
  34. data/lib/makit/commands/middleware/validator.rb +269 -0
  35. data/lib/makit/commands/request.rb +254 -0
  36. data/lib/makit/commands/result.rb +323 -0
  37. data/lib/makit/commands/runner.rb +317 -0
  38. data/lib/makit/commands/strategies/base.rb +160 -0
  39. data/lib/makit/commands/strategies/synchronous.rb +134 -0
  40. data/lib/makit/commands.rb +24 -3
  41. data/lib/makit/configuration/gitlab_helper.rb +60 -0
  42. data/lib/makit/configuration/project.rb +127 -0
  43. data/lib/makit/configuration/rakefile_helper.rb +43 -0
  44. data/lib/makit/configuration/step.rb +34 -0
  45. data/lib/makit/configuration.rb +14 -0
  46. data/lib/makit/content/default_gitignore.rb +4 -2
  47. data/lib/makit/content/default_rakefile.rb +4 -2
  48. data/lib/makit/content/gem_rakefile.rb +4 -2
  49. data/lib/makit/context.rb +1 -0
  50. data/lib/makit/data.rb +9 -10
  51. data/lib/makit/directories.rb +48 -52
  52. data/lib/makit/directory.rb +38 -52
  53. data/lib/makit/docs/files.rb +5 -10
  54. data/lib/makit/docs/rake.rb +16 -20
  55. data/lib/makit/dotnet/cli.rb +65 -0
  56. data/lib/makit/dotnet/project.rb +153 -0
  57. data/lib/makit/dotnet/solution.rb +38 -0
  58. data/lib/makit/dotnet/solution_classlib.rb +239 -0
  59. data/lib/makit/dotnet/solution_console.rb +264 -0
  60. data/lib/makit/dotnet/solution_maui.rb +354 -0
  61. data/lib/makit/dotnet/solution_wasm.rb +275 -0
  62. data/lib/makit/dotnet/solution_wpf.rb +304 -0
  63. data/lib/makit/dotnet.rb +54 -171
  64. data/lib/makit/email.rb +46 -17
  65. data/lib/makit/environment.rb +22 -19
  66. data/lib/makit/examples/runner.rb +370 -0
  67. data/lib/makit/exceptions.rb +45 -0
  68. data/lib/makit/fileinfo.rb +3 -5
  69. data/lib/makit/files.rb +12 -16
  70. data/lib/makit/gems.rb +40 -39
  71. data/lib/makit/git/cli.rb +54 -0
  72. data/lib/makit/git/repository.rb +90 -0
  73. data/lib/makit/git.rb +44 -91
  74. data/lib/makit/gitlab_runner.rb +0 -1
  75. data/lib/makit/humanize.rb +31 -23
  76. data/lib/makit/indexer.rb +15 -24
  77. data/lib/makit/logging/configuration.rb +305 -0
  78. data/lib/makit/logging/format_registry.rb +84 -0
  79. data/lib/makit/logging/formatters/base.rb +39 -0
  80. data/lib/makit/logging/formatters/console_formatter.rb +127 -0
  81. data/lib/makit/logging/formatters/json_formatter.rb +65 -0
  82. data/lib/makit/logging/formatters/plain_text_formatter.rb +71 -0
  83. data/lib/makit/logging/formatters/text_formatter.rb +64 -0
  84. data/lib/makit/logging/log_request.rb +115 -0
  85. data/lib/makit/logging/logger.rb +159 -0
  86. data/lib/makit/logging/sinks/base.rb +91 -0
  87. data/lib/makit/logging/sinks/console.rb +72 -0
  88. data/lib/makit/logging/sinks/file_sink.rb +92 -0
  89. data/lib/makit/logging/sinks/structured.rb +129 -0
  90. data/lib/makit/logging/sinks/unified_file_sink.rb +303 -0
  91. data/lib/makit/logging.rb +452 -37
  92. data/lib/makit/markdown.rb +18 -18
  93. data/lib/makit/mp/basic_object_mp.rb +5 -4
  94. data/lib/makit/mp/command_mp.rb +5 -5
  95. data/lib/makit/mp/command_request.mp.rb +3 -2
  96. data/lib/makit/mp/project_mp.rb +85 -96
  97. data/lib/makit/mp/string_mp.rb +245 -73
  98. data/lib/makit/nuget.rb +27 -25
  99. data/lib/makit/port.rb +25 -27
  100. data/lib/makit/process.rb +127 -29
  101. data/lib/makit/protoc.rb +27 -24
  102. data/lib/makit/rake/cli.rb +196 -0
  103. data/lib/makit/rake.rb +6 -6
  104. data/lib/makit/ruby/cli.rb +185 -0
  105. data/lib/makit/ruby.rb +25 -0
  106. data/lib/makit/secrets.rb +18 -18
  107. data/lib/makit/serializer.rb +29 -27
  108. data/lib/makit/services/builder.rb +186 -0
  109. data/lib/makit/services/error_handler.rb +226 -0
  110. data/lib/makit/services/repository_manager.rb +229 -0
  111. data/lib/makit/services/validator.rb +112 -0
  112. data/lib/makit/setup/classlib.rb +53 -0
  113. data/lib/makit/setup/gem.rb +250 -0
  114. data/lib/makit/setup/runner.rb +40 -0
  115. data/lib/makit/show.rb +16 -16
  116. data/lib/makit/storage.rb +32 -37
  117. data/lib/makit/symbols.rb +12 -0
  118. data/lib/makit/task_hooks.rb +125 -0
  119. data/lib/makit/task_info.rb +63 -21
  120. data/lib/makit/tasks/at_exit.rb +13 -0
  121. data/lib/makit/tasks/build.rb +18 -0
  122. data/lib/makit/tasks/clean.rb +11 -0
  123. data/lib/makit/tasks/hook_manager.rb +239 -0
  124. data/lib/makit/tasks/init.rb +47 -0
  125. data/lib/makit/tasks/integrate.rb +15 -0
  126. data/lib/makit/tasks/pull_incoming.rb +12 -0
  127. data/lib/makit/tasks/setup.rb +6 -0
  128. data/lib/makit/tasks/sync.rb +11 -0
  129. data/lib/makit/tasks/task_monkey_patch.rb +79 -0
  130. data/lib/makit/tasks.rb +5 -150
  131. data/lib/makit/test_cache.rb +239 -0
  132. data/lib/makit/v1/makit.v1_pb.rb +34 -35
  133. data/lib/makit/v1/makit.v1_services_pb.rb +2 -0
  134. data/lib/makit/version.rb +1 -60
  135. data/lib/makit/wix.rb +23 -23
  136. data/lib/makit/yaml.rb +18 -6
  137. data/lib/makit.rb +2 -261
  138. metadata +109 -145
  139. data/lib/makit/cli/clean.rb +0 -14
  140. data/lib/makit/cli/clone.rb +0 -59
  141. data/lib/makit/cli/init.rb +0 -38
  142. data/lib/makit/cli/make.rb +0 -54
  143. data/lib/makit/cli/new.rb +0 -37
  144. data/lib/makit/cli/nuget_cache.rb +0 -38
  145. data/lib/makit/cli/pull.rb +0 -31
  146. data/lib/makit/cli/setup.rb +0 -71
  147. data/lib/makit/cli/work.rb +0 -21
  148. data/lib/makit/content/default_gitignore.txt +0 -222
@@ -0,0 +1,305 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Makit
4
+ module Logging
5
+ # Configuration management for unified logging
6
+ #
7
+ # Provides schema validation, default configurations, and helper methods
8
+ # for setting up the unified file sink with various output configurations.
9
+ #
10
+ # @example Basic configuration
11
+ # config = Configuration.new(
12
+ # configurations: [
13
+ # { file: $stdout, format: :console },
14
+ # { file: "logs/app.log", format: :json }
15
+ # ]
16
+ # )
17
+ #
18
+ # @example YAML configuration
19
+ # config = Configuration.from_yaml("config/logging.yml")
20
+ #
21
+ # @example Environment-based configuration
22
+ # config = Configuration.for_environment(:production)
23
+ class Configuration
24
+ # @return [Array<Hash>] list of output configurations
25
+ attr_reader :configurations
26
+
27
+ # Initialize configuration
28
+ #
29
+ # @param configurations [Array<Hash>] list of output configurations
30
+ def initialize(configurations: [])
31
+ @configurations = configurations
32
+ end
33
+
34
+ # Create configuration from YAML file
35
+ #
36
+ # @param yaml_file [String] path to YAML configuration file
37
+ # @return [Configuration] new configuration instance
38
+ def self.from_yaml(yaml_file)
39
+ require "yaml"
40
+ data = YAML.load_file(yaml_file)
41
+ configurations = data["logging"]["sinks"] || []
42
+
43
+ # Convert string keys to symbols
44
+ configurations = configurations.map do |config|
45
+ config.transform_keys(&:to_sym)
46
+ end
47
+
48
+ new(configurations: configurations)
49
+ end
50
+
51
+ # Create configuration from JSON file
52
+ #
53
+ # @param json_file [String] path to JSON configuration file
54
+ # @return [Configuration] new configuration instance
55
+ def self.from_json(json_file)
56
+ require "json"
57
+ data = JSON.parse(File.read(json_file))
58
+ configurations = data["logging"]["sinks"] || []
59
+
60
+ # Convert string keys to symbols
61
+ configurations = configurations.map do |config|
62
+ config.transform_keys(&:to_sym)
63
+ end
64
+
65
+ new(configurations: configurations)
66
+ end
67
+
68
+ # Create environment-specific configuration
69
+ #
70
+ # @param environment [Symbol] environment name (:development, :production, :test)
71
+ # @return [Configuration] new configuration instance
72
+ def self.for_environment(environment)
73
+ case environment
74
+ when :development
75
+ development_config
76
+ when :production
77
+ production_config
78
+ when :test
79
+ test_config
80
+ when :ci
81
+ ci_config
82
+ else
83
+ default_config
84
+ end
85
+ end
86
+
87
+ # Get default configuration
88
+ #
89
+ # @return [Configuration] default configuration
90
+ def self.default_config
91
+ new(
92
+ configurations: [
93
+ { file: $stdout, format: :console },
94
+ { file: "artifacts/makit.log", format: :json, append: true },
95
+ ],
96
+ )
97
+ end
98
+
99
+ # Get development configuration
100
+ #
101
+ # @return [Configuration] development configuration
102
+ def self.development_config
103
+ new(
104
+ configurations: [
105
+ {
106
+ file: $stdout,
107
+ format: :console,
108
+ show_timestamp: true,
109
+ show_level: true,
110
+ },
111
+ {
112
+ file: "logs/development.log",
113
+ format: :text,
114
+ append: true,
115
+ include_context: true,
116
+ },
117
+ {
118
+ file: "logs/debug.log",
119
+ format: :json,
120
+ append: true,
121
+ min_level: :debug,
122
+ },
123
+ ],
124
+ )
125
+ end
126
+
127
+ # Get production configuration
128
+ #
129
+ # @return [Configuration] production configuration
130
+ def self.production_config
131
+ new(
132
+ configurations: [
133
+ {
134
+ file: "logs/application.log",
135
+ format: :json,
136
+ append: true,
137
+ include_metadata: true,
138
+ rotation: { max_size: "100MB", max_files: 10 },
139
+ },
140
+ {
141
+ file: "logs/errors.log",
142
+ format: :json,
143
+ append: true,
144
+ min_level: :error,
145
+ include_metadata: true,
146
+ },
147
+ ],
148
+ )
149
+ end
150
+
151
+ # Get test configuration
152
+ #
153
+ # @return [Configuration] test configuration
154
+ def self.test_config
155
+ new(
156
+ configurations: [
157
+ {
158
+ file: "logs/test.log",
159
+ format: :text,
160
+ append: false,
161
+ include_context: true,
162
+ },
163
+ ],
164
+ )
165
+ end
166
+
167
+ # Get CI/CD configuration
168
+ #
169
+ # @return [Configuration] CI configuration
170
+ def self.ci_config
171
+ new(
172
+ configurations: [
173
+ {
174
+ file: $stdout,
175
+ format: :console,
176
+ show_level: true,
177
+ },
178
+ {
179
+ file: "artifacts/build.log",
180
+ format: :json,
181
+ append: true,
182
+ include_metadata: true,
183
+ },
184
+ ],
185
+ )
186
+ end
187
+
188
+ # Validate configuration
189
+ #
190
+ # @return [Boolean] true if valid
191
+ # @raise [ArgumentError] if configuration is invalid
192
+ def validate!
193
+ raise ArgumentError, "configurations must be an array" unless @configurations.is_a?(Array)
194
+ raise ArgumentError, "at least one configuration is required" if @configurations.empty?
195
+
196
+ @configurations.each_with_index do |config, index|
197
+ validate_single_configuration(config, index)
198
+ end
199
+
200
+ true
201
+ end
202
+
203
+ # Check if configuration is valid
204
+ #
205
+ # @return [Boolean] true if valid
206
+ def valid?
207
+ validate!
208
+ true
209
+ rescue ArgumentError
210
+ false
211
+ end
212
+
213
+ # Get configuration as hash
214
+ #
215
+ # @return [Hash] configuration as hash
216
+ def to_hash
217
+ {
218
+ logging: {
219
+ sinks: @configurations,
220
+ },
221
+ }
222
+ end
223
+
224
+ # Save configuration to YAML file
225
+ #
226
+ # @param yaml_file [String] path to YAML file
227
+ # @return [void]
228
+ def save_yaml(yaml_file)
229
+ require "yaml"
230
+ FileUtils.mkdir_p(File.dirname(yaml_file))
231
+ File.write(yaml_file, to_hash.to_yaml)
232
+ end
233
+
234
+ # Save configuration to JSON file
235
+ #
236
+ # @param json_file [String] path to JSON file
237
+ # @return [void]
238
+ def save_json(json_file)
239
+ require "json"
240
+ FileUtils.mkdir_p(File.dirname(json_file))
241
+ File.write(json_file, JSON.pretty_generate(to_hash))
242
+ end
243
+
244
+ private
245
+
246
+ # Validate a single configuration
247
+ #
248
+ # @param config [Hash] configuration to validate
249
+ # @param index [Integer] configuration index for error messages
250
+ # @raise [ArgumentError] if configuration is invalid
251
+ def validate_single_configuration(config, index)
252
+ raise ArgumentError, "configuration #{index} must be a hash" unless config.is_a?(Hash)
253
+
254
+ required_keys = [:file, :format]
255
+ missing_keys = required_keys - config.keys
256
+ raise ArgumentError, "configuration #{index} missing required keys: #{missing_keys.join(", ")}" unless missing_keys.empty?
257
+
258
+ # Validate file
259
+ file = config[:file]
260
+ unless file.is_a?(String) || file.is_a?(IO) || file.respond_to?(:write)
261
+ raise ArgumentError, "configuration #{index} file must be a String path, IO object, or writable object"
262
+ end
263
+
264
+ # Validate format
265
+ format = config[:format]
266
+ unless format.is_a?(Symbol) || format.is_a?(String)
267
+ raise ArgumentError, "configuration #{index} format must be a Symbol or String"
268
+ end
269
+
270
+ # Validate log levels if specified
271
+ if config[:min_level] && !valid_log_level?(config[:min_level])
272
+ raise ArgumentError, "configuration #{index} min_level must be a valid log level"
273
+ end
274
+
275
+ if config[:max_level] && !valid_log_level?(config[:max_level])
276
+ raise ArgumentError, "configuration #{index} max_level must be a valid log level"
277
+ end
278
+
279
+ # Validate rotation if specified
280
+ if config[:rotation] && !valid_rotation_config?(config[:rotation])
281
+ raise ArgumentError, "configuration #{index} rotation must be a valid rotation configuration"
282
+ end
283
+ end
284
+
285
+ # Check if log level is valid
286
+ #
287
+ # @param level [Symbol] log level to check
288
+ # @return [Boolean] true if valid
289
+ def valid_log_level?(level)
290
+ %i[debug info warn error fatal success].include?(level)
291
+ end
292
+
293
+ # Check if rotation configuration is valid
294
+ #
295
+ # @param rotation [Hash] rotation configuration
296
+ # @return [Boolean] true if valid
297
+ def valid_rotation_config?(rotation)
298
+ return false unless rotation.is_a?(Hash)
299
+
300
+ valid_keys = [:max_size, :max_files, :compress, :pattern]
301
+ rotation.keys.all? { |key| valid_keys.include?(key) }
302
+ end
303
+ end
304
+ end
305
+ end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Makit
4
+ module Logging
5
+ # Registry for managing available log formatters
6
+ #
7
+ # Provides a centralized way to register, retrieve, and manage formatters
8
+ # by name. This allows for easy extension and configuration of formatters.
9
+ #
10
+ # @example Registering a custom formatter
11
+ # FormatRegistry.register(:audit, AuditFormatter)
12
+ # formatter = FormatRegistry.get(:audit).new
13
+ #
14
+ # @example Using built-in formatters
15
+ # formatter = FormatRegistry.get(:json).new
16
+ # formatter = FormatRegistry.get(:text).new(timestamp_format: "%H:%M:%S")
17
+ class FormatRegistry
18
+ @formatters = {}
19
+
20
+ class << self
21
+ # @return [Hash] registered formatters
22
+ attr_reader :formatters
23
+
24
+ # Register a formatter class with a name
25
+ #
26
+ # @param name [Symbol, String] the name to register the formatter under
27
+ # @param formatter_class [Class] the formatter class to register
28
+ # @return [void]
29
+ def register(name, formatter_class)
30
+ @formatters[name.to_sym] = formatter_class
31
+ end
32
+
33
+ # Get a formatter class by name
34
+ #
35
+ # @param name [Symbol, String] the name of the formatter
36
+ # @return [Class] the formatter class
37
+ # @raise [ArgumentError] if formatter is not found
38
+ def get(name)
39
+ @formatters[name.to_sym] || raise(ArgumentError, "Unknown formatter: #{name}")
40
+ end
41
+
42
+ # Get all available formatter names
43
+ #
44
+ # @return [Array<Symbol>] list of registered formatter names
45
+ def available_formats
46
+ @formatters.keys
47
+ end
48
+
49
+ # Check if a formatter is registered
50
+ #
51
+ # @param name [Symbol, String] the name to check
52
+ # @return [Boolean] true if formatter is registered
53
+ def registered?(name)
54
+ @formatters.key?(name.to_sym)
55
+ end
56
+
57
+ # Clear all registered formatters
58
+ #
59
+ # @return [void]
60
+ def clear
61
+ @formatters.clear
62
+ end
63
+
64
+ # Register built-in formatters
65
+ #
66
+ # @return [void]
67
+ def register_built_ins
68
+ require_relative "formatters/json_formatter"
69
+ require_relative "formatters/text_formatter"
70
+ require_relative "formatters/plain_text_formatter"
71
+ require_relative "formatters/console_formatter"
72
+
73
+ register(:json, Formatters::JsonFormatter)
74
+ register(:text, Formatters::TextFormatter)
75
+ register(:plain, Formatters::PlainTextFormatter)
76
+ register(:console, Formatters::ConsoleFormatter)
77
+ end
78
+ end
79
+
80
+ # Initialize registry with built-in formatters
81
+ register_built_ins
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Makit
4
+ module Logging
5
+ module Formatters
6
+ # Base class for all logging formatters
7
+ #
8
+ # Formatters handle the conversion of log requests into formatted strings
9
+ # that can be written to various outputs (console, files, etc.).
10
+ # This separates formatting concerns from output routing concerns.
11
+ #
12
+ # @example Creating a custom formatter
13
+ # class CustomFormatter < Base
14
+ # def format(log_request)
15
+ # "#{log_request.level.upcase}: #{log_request.message}"
16
+ # end
17
+ # end
18
+ class Base
19
+ # Format a log request into a string
20
+ #
21
+ # @param log_request [LogRequest] the log request to format
22
+ # @return [String] the formatted log entry
23
+ def format(log_request)
24
+ raise NotImplementedError, "Subclasses must implement #format"
25
+ end
26
+
27
+ # Get formatter configuration
28
+ #
29
+ # @return [Hash] formatter configuration
30
+ def config
31
+ {
32
+ name: self.class.name.split("::").last,
33
+ type: self.class.name,
34
+ }
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,127 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "colorize"
4
+ require_relative "base"
5
+
6
+ module Makit
7
+ module Logging
8
+ module Formatters
9
+ # Console formatter for colored log output
10
+ #
11
+ # Formats log requests for console display with colors, symbols, and optional
12
+ # timestamps/levels. This is specifically designed for human-readable console output.
13
+ #
14
+ # @example
15
+ # formatter = ConsoleFormatter.new
16
+ # formatted = formatter.format(log_request)
17
+ # # => "→ Processing started" (with appropriate color)
18
+ class ConsoleFormatter < Base
19
+ # @return [Boolean] whether to show timestamps
20
+ attr_reader :show_timestamp
21
+ # @return [Boolean] whether to show log levels
22
+ attr_reader :show_level
23
+
24
+ # Initialize console formatter
25
+ #
26
+ # @param show_timestamp [Boolean] whether to show timestamps (default: false)
27
+ # @param show_level [Boolean] whether to show log levels (default: false)
28
+ def initialize(show_timestamp: false, show_level: false)
29
+ @show_timestamp = show_timestamp
30
+ @show_level = show_level
31
+ end
32
+
33
+ # Format log request for console display
34
+ #
35
+ # @param log_request [LogRequest] the log request to format
36
+ # @return [String] console formatted log entry with colors
37
+ def format(log_request)
38
+ parts = []
39
+
40
+ # Add timestamp if enabled
41
+ if @show_timestamp
42
+ timestamp = log_request.timestamp.strftime("%H:%M:%S")
43
+ parts << "[#{timestamp}]".colorize(:light_black)
44
+ end
45
+
46
+ # Add log level if enabled
47
+ if @show_level
48
+ level_str = log_request.level.to_s.upcase
49
+ level_color = get_level_color(log_request.level)
50
+ parts << level_str.colorize(level_color)
51
+ end
52
+
53
+ # Add symbol and message
54
+ symbol = get_level_symbol(log_request.level)
55
+ symbol_color = get_level_color(log_request.level)
56
+ message = log_request.message
57
+
58
+ # Add context if present
59
+ if !log_request.context.empty?
60
+ context_str = log_request.context.map { |k, v| "#{k}=#{v}" }.join(" ")
61
+ message += " #{context_str}".colorize(:light_black)
62
+ end
63
+
64
+ parts << "#{symbol} #{message}".colorize(symbol_color)
65
+
66
+ parts.join(" ")
67
+ end
68
+
69
+ # Get formatter configuration
70
+ #
71
+ # @return [Hash] formatter configuration
72
+ def config
73
+ super.merge(
74
+ show_timestamp: @show_timestamp,
75
+ show_level: @show_level,
76
+ )
77
+ end
78
+
79
+ private
80
+
81
+ # Get the color for a log level
82
+ #
83
+ # @param level [Symbol] the log level
84
+ # @return [Symbol] the color for the level
85
+ def get_level_color(level)
86
+ case level
87
+ when :debug
88
+ :grey
89
+ when :info
90
+ :grey
91
+ when :warn
92
+ :light_yellow
93
+ when :error, :fatal
94
+ :light_red
95
+ when :success
96
+ :green
97
+ else
98
+ :white
99
+ end
100
+ end
101
+
102
+ # Get the symbol for a log level
103
+ #
104
+ # @param level [Symbol] the log level
105
+ # @return [String] the symbol for the level
106
+ def get_level_symbol(level)
107
+ case level
108
+ when :debug
109
+ "•"
110
+ when :info
111
+ " " #"→"
112
+ when :warn
113
+ "!" #"⚠"
114
+ when :error
115
+ "✗"
116
+ when :fatal
117
+ "💀"
118
+ when :success
119
+ "✓"
120
+ else
121
+ "•"
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require_relative "base"
5
+
6
+ module Makit
7
+ module Logging
8
+ module Formatters
9
+ # JSON formatter for structured logging
10
+ #
11
+ # Formats log requests as JSON objects with timestamp, level, message, and context.
12
+ # This is ideal for log aggregation systems and structured data analysis.
13
+ #
14
+ # @example
15
+ # formatter = JsonFormatter.new
16
+ # formatted = formatter.format(log_request)
17
+ # # => '{"timestamp":"2024-01-15T10:30:45Z","level":"INFO","message":"User logged in","context":{"user_id":123}}'
18
+ class JsonFormatter < Base
19
+ # @return [Hash] additional options for JSON formatting
20
+ attr_reader :options
21
+
22
+ # Initialize JSON formatter
23
+ #
24
+ # @param options [Hash] JSON generation options
25
+ def initialize(options: {})
26
+ @options = {
27
+ indent: nil,
28
+ space: nil,
29
+ space_before: nil,
30
+ object_nl: nil,
31
+ array_nl: nil,
32
+ allow_nan: false,
33
+ max_nesting: 100,
34
+ }.merge(options)
35
+ end
36
+
37
+ # Format log request as JSON
38
+ #
39
+ # @param log_request [LogRequest] the log request to format
40
+ # @return [String] JSON formatted log entry
41
+ def format(log_request)
42
+ log_data = {
43
+ timestamp: log_request.timestamp.iso8601,
44
+ level: log_request.level.to_s.upcase,
45
+ message: log_request.message,
46
+ }
47
+
48
+ # Add context if present
49
+ log_data[:context] = log_request.context unless log_request.context.empty?
50
+
51
+ JSON.generate(log_data, @options)
52
+ end
53
+
54
+ # Get formatter configuration
55
+ #
56
+ # @return [Hash] formatter configuration including JSON options
57
+ def config
58
+ super.merge(
59
+ json_options: @options,
60
+ )
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
4
+
5
+ module Makit
6
+ module Logging
7
+ module Formatters
8
+ # Plain text formatter with just the message
9
+ #
10
+ # Formats log requests as plain text containing only the message content.
11
+ # This is useful for simple log files where only the message matters.
12
+ #
13
+ # @example
14
+ # formatter = PlainTextFormatter.new
15
+ # formatted = formatter.format(log_request)
16
+ # # => 'User logged in'
17
+ class PlainTextFormatter < Base
18
+ # @return [Boolean] whether to include context in output
19
+ attr_reader :include_context
20
+
21
+ # Initialize plain text formatter
22
+ #
23
+ # @param include_context [Boolean] whether to include context in output
24
+ def initialize(include_context: false)
25
+ @include_context = include_context
26
+ end
27
+
28
+ # Format log request as plain text
29
+ #
30
+ # @param log_request [LogRequest] the log request to format
31
+ # @return [String] plain text formatted log entry
32
+ def format(log_request)
33
+ message = log_request.message
34
+
35
+ # Add context if enabled and present
36
+ if @include_context && !log_request.context.empty?
37
+ # Create a more readable context representation
38
+ context_parts = log_request.context.map do |k, v|
39
+ # Format values nicely based on their type
40
+ formatted_value = case v
41
+ when String
42
+ v.include?(" ") ? "\"#{v}\"" : v
43
+ when Hash, Array
44
+ v.inspect
45
+ when Time
46
+ v.strftime("%Y-%m-%d %H:%M:%S")
47
+ else
48
+ v.to_s
49
+ end
50
+ "#{k}: #{formatted_value}"
51
+ end
52
+
53
+ context_str = context_parts.join(", ")
54
+ message += " (#{context_str})"
55
+ end
56
+
57
+ message
58
+ end
59
+
60
+ # Get formatter configuration
61
+ #
62
+ # @return [Hash] formatter configuration
63
+ def config
64
+ super.merge(
65
+ include_context: @include_context,
66
+ )
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end