Class: A2A::Utils::StructuredLogger
- Inherits:
-
Object
- Object
- A2A::Utils::StructuredLogger
- Defined in:
- lib/a2a/utils/structured_logger.rb
Constant Summary collapse
- LEVELS =
Log levels
{ debug: Logger::DEBUG, info: Logger::INFO, warn: Logger::WARN, error: Logger::ERROR, fatal: Logger::FATAL }.freeze
Instance Attribute Summary collapse
-
#correlation_id ⇒ Object
Returns the value of attribute correlation_id.
-
#logger ⇒ Object
readonly
Returns the value of attribute logger.
-
#service_name ⇒ Object
readonly
Returns the value of attribute service_name.
-
#version ⇒ Object
readonly
Returns the value of attribute version.
Instance Method Summary collapse
-
#build_log_entry(level, message, **context) ⇒ Hash
private
Build structured log entry.
-
#child(**context) ⇒ StructuredLogger
Create a child logger with additional context.
-
#debug(message, **context) ⇒ Object
Log a debug message.
-
#error(message, error: nil, **context) ⇒ Object
Log an error message.
-
#fatal(message, error: nil, **context) ⇒ Object
Log a fatal message.
-
#format_error(error) ⇒ Hash
private
Format error information.
-
#format_log_entry(severity, _datetime, _progname, msg) ⇒ String
private
Format log entry for output.
-
#generate_correlation_id ⇒ String
Generate a new correlation ID.
-
#http_request(method:, url:, status:, duration:, **context) ⇒ Object
Log HTTP request/response.
-
#info(message, **context) ⇒ Object
Log an info message.
-
#initialize(output: $stdout, level: :info, service_name: "a2a-ruby", version: A2A::VERSION, correlation_id: nil) ⇒ StructuredLogger
constructor
Initialize structured logger.
-
#log(level, message, **context) ⇒ Object
private
Log a message with structured data.
-
#metric(metric_name, value, unit: nil, **tags) ⇒ Object
Log performance metrics.
-
#stats ⇒ Hash
Get logger statistics.
-
#task_operation(operation:, task_id:, context_id: nil, status: nil, **context) ⇒ Object
Log task operation.
-
#timed(message, level: :info, **context) { ... } ⇒ Object
Log with timing information.
-
#warn(message, **context) ⇒ Object
Log a warning message.
Constructor Details
#initialize(output: $stdout, level: :info, service_name: "a2a-ruby", version: A2A::VERSION, correlation_id: nil) ⇒ StructuredLogger
Initialize structured logger
36 37 38 39 40 41 42 43 44 45 |
# File 'lib/a2a/utils/structured_logger.rb', line 36 def initialize(output: $stdout, level: :info, service_name: "a2a-ruby", version: A2A::VERSION, correlation_id: nil) @logger = Logger.new(output) @logger.level = LEVELS[level] || level @logger.formatter = method(:format_log_entry) @service_name = service_name @version = version @correlation_id = correlation_id || generate_correlation_id @start_time = Time.now end |
Instance Attribute Details
#correlation_id ⇒ Object
Returns the value of attribute correlation_id.
25 26 27 |
# File 'lib/a2a/utils/structured_logger.rb', line 25 def correlation_id @correlation_id end |
#logger ⇒ Object (readonly)
Returns the value of attribute logger.
26 27 28 |
# File 'lib/a2a/utils/structured_logger.rb', line 26 def logger @logger end |
#service_name ⇒ Object (readonly)
Returns the value of attribute service_name.
26 27 28 |
# File 'lib/a2a/utils/structured_logger.rb', line 26 def service_name @service_name end |
#version ⇒ Object (readonly)
Returns the value of attribute version.
26 27 28 |
# File 'lib/a2a/utils/structured_logger.rb', line 26 def version @version end |
Instance Method Details
#build_log_entry(level, message, **context) ⇒ Hash (private)
Build structured log entry
261 262 263 264 265 266 267 268 269 270 271 272 |
# File 'lib/a2a/utils/structured_logger.rb', line 261 def build_log_entry(level, , **context) { timestamp: Time.now.utc.iso8601(3), level: level.to_s.upcase, message: , service: @service_name, version: @version, correlation_id: @correlation_id, thread_id: Thread.current.object_id, **context } end |
#child(**context) ⇒ StructuredLogger
Create a child logger with additional context
195 196 197 198 199 200 201 202 203 204 205 206 |
# File 'lib/a2a/utils/structured_logger.rb', line 195 def child(**context) child_logger = self.class.new( output: @logger.instance_variable_get(:@logdev).dev, level: @logger.level, service_name: @service_name, version: @version, correlation_id: @correlation_id ) child_logger.instance_variable_set(:@additional_context, context) child_logger end |
#debug(message, **context) ⇒ Object
Log a debug message
52 53 54 |
# File 'lib/a2a/utils/structured_logger.rb', line 52 def debug(, **context) log(:debug, , **context) end |
#error(message, error: nil, **context) ⇒ Object
Log an error message
80 81 82 83 |
# File 'lib/a2a/utils/structured_logger.rb', line 80 def error(, error: nil, **context) context[:error] = format_error(error) if error log(:error, , **context) end |
#fatal(message, error: nil, **context) ⇒ Object
Log a fatal message
91 92 93 94 |
# File 'lib/a2a/utils/structured_logger.rb', line 91 def fatal(, error: nil, **context) context[:error] = format_error(error) if error log(:fatal, , **context) end |
#format_error(error) ⇒ Hash (private)
Format error information
297 298 299 300 301 302 303 |
# File 'lib/a2a/utils/structured_logger.rb', line 297 def format_error(error) { class: error.class.name, message: error., backtrace: error.backtrace&.first(10) # Limit backtrace length } end |
#format_log_entry(severity, _datetime, _progname, msg) ⇒ String (private)
Format log entry for output
282 283 284 285 286 287 288 289 290 |
# File 'lib/a2a/utils/structured_logger.rb', line 282 def format_log_entry(severity, _datetime, _progname, msg) if msg.is_a?(Hash) "#{JSON.generate(msg)}\n" else # Fallback for non-structured messages entry = build_log_entry(severity.downcase.to_sym, msg.to_s) "#{JSON.generate(entry)}\n" end end |
#generate_correlation_id ⇒ String
Generate a new correlation ID
217 218 219 |
# File 'lib/a2a/utils/structured_logger.rb', line 217 def generate_correlation_id SecureRandom.hex(8) end |
#http_request(method:, url:, status:, duration:, **context) ⇒ Object
Log HTTP request/response
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
# File 'lib/a2a/utils/structured_logger.rb', line 132 def http_request(method:, url:, status:, duration:, **context) log_data = { http_method: method.to_s.upcase, url: url, status_code: status, duration: duration, **context } level = case status when 200..299 then :info when 300..399 then :info when 400..499 then :warn when 500..599 then :error else :info end log(level, "HTTP #{method.upcase} #{url}", **log_data) end |
#info(message, **context) ⇒ Object
Log an info message
61 62 63 |
# File 'lib/a2a/utils/structured_logger.rb', line 61 def info(, **context) log(:info, , **context) end |
#log(level, message, **context) ⇒ Object (private)
Log a message with structured data
243 244 245 246 247 248 249 250 251 252 |
# File 'lib/a2a/utils/structured_logger.rb', line 243 def log(level, , **context) return unless @logger.public_send("#{level}?") # Merge additional context from child loggers additional_context = instance_variable_get(:@additional_context) || {} context = additional_context.merge(context) log_entry = build_log_entry(level, , **context) @logger.public_send(level, log_entry) end |
#metric(metric_name, value, unit: nil, **tags) ⇒ Object
Log performance metrics
179 180 181 182 183 184 185 186 187 188 |
# File 'lib/a2a/utils/structured_logger.rb', line 179 def metric(metric_name, value, unit: nil, **) log_data = { metric_name: metric_name, metric_value: value, metric_unit: unit, metric_tags: }.compact log(:info, "Metric: #{metric_name}", **log_data) end |
#stats ⇒ Hash
Get logger statistics
225 226 227 228 229 230 231 232 233 |
# File 'lib/a2a/utils/structured_logger.rb', line 225 def stats { service_name: @service_name, version: @version, correlation_id: @correlation_id, uptime: Time.now - @start_time, log_level: @logger.level } end |
#task_operation(operation:, task_id:, context_id: nil, status: nil, **context) ⇒ Object
Log task operation
160 161 162 163 164 165 166 167 168 169 170 |
# File 'lib/a2a/utils/structured_logger.rb', line 160 def task_operation(operation:, task_id:, context_id: nil, status: nil, **context) log_data = { operation: operation, task_id: task_id, context_id: context_id, task_status: status, **context }.compact log(:info, "Task #{operation}", **log_data) end |
#timed(message, level: :info, **context) { ... } ⇒ Object
Log with timing information
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
# File 'lib/a2a/utils/structured_logger.rb', line 104 def timed(, level: :info, **context) start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC) begin result = yield duration = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start_time log(level, "#{} completed", duration: duration, **context) result rescue StandardError => e duration = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start_time error("#{} failed", error: e, duration: duration, **context) raise end end |
#warn(message, **context) ⇒ Object
Log a warning message
70 71 72 |
# File 'lib/a2a/utils/structured_logger.rb', line 70 def warn(, **context) log(:warn, , **context) end |