a2a-ruby 1.0.0
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.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +137 -0
- data/.simplecov +46 -0
- data/.yardopts +10 -0
- data/CHANGELOG.md +33 -0
- data/CODE_OF_CONDUCT.md +128 -0
- data/CONTRIBUTING.md +165 -0
- data/Gemfile +43 -0
- data/Guardfile +34 -0
- data/LICENSE.txt +21 -0
- data/PUBLISHING_CHECKLIST.md +214 -0
- data/README.md +171 -0
- data/Rakefile +165 -0
- data/docs/agent_execution.md +309 -0
- data/docs/api_reference.md +792 -0
- data/docs/configuration.md +780 -0
- data/docs/events.md +475 -0
- data/docs/getting_started.md +668 -0
- data/docs/integration.md +262 -0
- data/docs/server_apps.md +621 -0
- data/docs/troubleshooting.md +765 -0
- data/lib/a2a/client/api_methods.rb +263 -0
- data/lib/a2a/client/auth/api_key.rb +161 -0
- data/lib/a2a/client/auth/interceptor.rb +288 -0
- data/lib/a2a/client/auth/jwt.rb +189 -0
- data/lib/a2a/client/auth/oauth2.rb +146 -0
- data/lib/a2a/client/auth.rb +137 -0
- data/lib/a2a/client/base.rb +316 -0
- data/lib/a2a/client/config.rb +210 -0
- data/lib/a2a/client/connection_pool.rb +233 -0
- data/lib/a2a/client/http_client.rb +524 -0
- data/lib/a2a/client/json_rpc_handler.rb +136 -0
- data/lib/a2a/client/middleware/circuit_breaker_interceptor.rb +245 -0
- data/lib/a2a/client/middleware/logging_interceptor.rb +371 -0
- data/lib/a2a/client/middleware/rate_limit_interceptor.rb +142 -0
- data/lib/a2a/client/middleware/retry_interceptor.rb +161 -0
- data/lib/a2a/client/middleware.rb +116 -0
- data/lib/a2a/client/performance_tracker.rb +60 -0
- data/lib/a2a/configuration/defaults.rb +34 -0
- data/lib/a2a/configuration/environment_loader.rb +76 -0
- data/lib/a2a/configuration/file_loader.rb +115 -0
- data/lib/a2a/configuration/inheritance.rb +101 -0
- data/lib/a2a/configuration/validator.rb +180 -0
- data/lib/a2a/configuration.rb +201 -0
- data/lib/a2a/errors.rb +291 -0
- data/lib/a2a/modules.rb +50 -0
- data/lib/a2a/monitoring/alerting.rb +490 -0
- data/lib/a2a/monitoring/distributed_tracing.rb +398 -0
- data/lib/a2a/monitoring/health_endpoints.rb +204 -0
- data/lib/a2a/monitoring/metrics_collector.rb +438 -0
- data/lib/a2a/monitoring.rb +463 -0
- data/lib/a2a/plugin.rb +358 -0
- data/lib/a2a/plugin_manager.rb +159 -0
- data/lib/a2a/plugins/example_auth.rb +81 -0
- data/lib/a2a/plugins/example_middleware.rb +118 -0
- data/lib/a2a/plugins/example_transport.rb +76 -0
- data/lib/a2a/protocol/agent_card.rb +8 -0
- data/lib/a2a/protocol/agent_card_server.rb +584 -0
- data/lib/a2a/protocol/capability.rb +496 -0
- data/lib/a2a/protocol/json_rpc.rb +254 -0
- data/lib/a2a/protocol/message.rb +8 -0
- data/lib/a2a/protocol/task.rb +8 -0
- data/lib/a2a/rails/a2a_controller.rb +258 -0
- data/lib/a2a/rails/controller_helpers.rb +499 -0
- data/lib/a2a/rails/engine.rb +167 -0
- data/lib/a2a/rails/generators/agent_generator.rb +311 -0
- data/lib/a2a/rails/generators/install_generator.rb +209 -0
- data/lib/a2a/rails/generators/migration_generator.rb +232 -0
- data/lib/a2a/rails/generators/templates/add_a2a_indexes.rb +57 -0
- data/lib/a2a/rails/generators/templates/agent_controller.rb +122 -0
- data/lib/a2a/rails/generators/templates/agent_controller_spec.rb +160 -0
- data/lib/a2a/rails/generators/templates/agent_readme.md +200 -0
- data/lib/a2a/rails/generators/templates/create_a2a_push_notification_configs.rb +68 -0
- data/lib/a2a/rails/generators/templates/create_a2a_tasks.rb +83 -0
- data/lib/a2a/rails/generators/templates/example_agent_controller.rb +228 -0
- data/lib/a2a/rails/generators/templates/initializer.rb +108 -0
- data/lib/a2a/rails/generators/templates/push_notification_config_model.rb +228 -0
- data/lib/a2a/rails/generators/templates/task_model.rb +200 -0
- data/lib/a2a/rails/tasks/a2a.rake +228 -0
- data/lib/a2a/server/a2a_methods.rb +520 -0
- data/lib/a2a/server/agent.rb +537 -0
- data/lib/a2a/server/agent_execution/agent_executor.rb +279 -0
- data/lib/a2a/server/agent_execution/request_context.rb +219 -0
- data/lib/a2a/server/apps/rack_app.rb +311 -0
- data/lib/a2a/server/apps/sinatra_app.rb +261 -0
- data/lib/a2a/server/default_request_handler.rb +350 -0
- data/lib/a2a/server/events/event_consumer.rb +116 -0
- data/lib/a2a/server/events/event_queue.rb +226 -0
- data/lib/a2a/server/example_agent.rb +248 -0
- data/lib/a2a/server/handler.rb +281 -0
- data/lib/a2a/server/middleware/authentication_middleware.rb +212 -0
- data/lib/a2a/server/middleware/cors_middleware.rb +171 -0
- data/lib/a2a/server/middleware/logging_middleware.rb +362 -0
- data/lib/a2a/server/middleware/rate_limit_middleware.rb +382 -0
- data/lib/a2a/server/middleware.rb +213 -0
- data/lib/a2a/server/push_notification_manager.rb +327 -0
- data/lib/a2a/server/request_handler.rb +136 -0
- data/lib/a2a/server/storage/base.rb +141 -0
- data/lib/a2a/server/storage/database.rb +266 -0
- data/lib/a2a/server/storage/memory.rb +274 -0
- data/lib/a2a/server/storage/redis.rb +320 -0
- data/lib/a2a/server/storage.rb +38 -0
- data/lib/a2a/server/task_manager.rb +534 -0
- data/lib/a2a/transport/grpc.rb +481 -0
- data/lib/a2a/transport/http.rb +415 -0
- data/lib/a2a/transport/sse.rb +499 -0
- data/lib/a2a/types/agent_card.rb +540 -0
- data/lib/a2a/types/artifact.rb +99 -0
- data/lib/a2a/types/base_model.rb +223 -0
- data/lib/a2a/types/events.rb +117 -0
- data/lib/a2a/types/message.rb +106 -0
- data/lib/a2a/types/part.rb +288 -0
- data/lib/a2a/types/push_notification.rb +139 -0
- data/lib/a2a/types/security.rb +167 -0
- data/lib/a2a/types/task.rb +154 -0
- data/lib/a2a/types.rb +88 -0
- data/lib/a2a/utils/helpers.rb +245 -0
- data/lib/a2a/utils/message_buffer.rb +278 -0
- data/lib/a2a/utils/performance.rb +247 -0
- data/lib/a2a/utils/rails_detection.rb +97 -0
- data/lib/a2a/utils/structured_logger.rb +306 -0
- data/lib/a2a/utils/time_helpers.rb +167 -0
- data/lib/a2a/utils/validation.rb +8 -0
- data/lib/a2a/version.rb +6 -0
- data/lib/a2a-rails.rb +58 -0
- data/lib/a2a.rb +198 -0
- metadata +437 -0
@@ -0,0 +1,463 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "logger"
|
4
|
+
require "json"
|
5
|
+
require_relative "monitoring/metrics_collector"
|
6
|
+
require_relative "monitoring/distributed_tracing"
|
7
|
+
require_relative "monitoring/alerting"
|
8
|
+
require_relative "monitoring/health_endpoints"
|
9
|
+
|
10
|
+
##
|
11
|
+
# Monitoring and metrics collection for A2A SDK
|
12
|
+
#
|
13
|
+
# Provides structured logging, metrics collection, and health checks
|
14
|
+
# with support for multiple backends including Prometheus.
|
15
|
+
#
|
16
|
+
module A2A
|
17
|
+
module Monitoring
|
18
|
+
class << self
|
19
|
+
# Global metrics collector
|
20
|
+
# @return [A2A::Monitoring::MetricsCollector]
|
21
|
+
attr_accessor :metrics
|
22
|
+
|
23
|
+
# Global logger with correlation ID support
|
24
|
+
# @return [A2A::Monitoring::StructuredLogger]
|
25
|
+
attr_accessor :logger
|
26
|
+
|
27
|
+
# Initialize monitoring system
|
28
|
+
# @param config [A2A::Configuration] Configuration instance
|
29
|
+
def initialize!(config = A2A.config)
|
30
|
+
@config = config
|
31
|
+
@metrics = MetricsCollector.new(config)
|
32
|
+
@logger = StructuredLogger.new(config)
|
33
|
+
@health_checks = HealthChecker.new(config)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Get metrics collector
|
37
|
+
# @return [A2A::Monitoring::MetricsCollector]
|
38
|
+
def metrics
|
39
|
+
@metrics ||= MetricsCollector.new(A2A.config)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Get structured logger
|
43
|
+
# @return [A2A::Monitoring::StructuredLogger]
|
44
|
+
def logger
|
45
|
+
@logger ||= StructuredLogger.new(A2A.config)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Get health checker
|
49
|
+
# @return [A2A::Monitoring::HealthChecker]
|
50
|
+
def health_checks
|
51
|
+
@health_checks ||= HealthChecker.new(A2A.config)
|
52
|
+
end
|
53
|
+
|
54
|
+
# Record a metric
|
55
|
+
# @param name [String] Metric name
|
56
|
+
# @param value [Numeric] Metric value
|
57
|
+
# @param **labels [Hash] Metric labels
|
58
|
+
def record_metric(name, value, **labels)
|
59
|
+
metrics.record(name, value, **labels)
|
60
|
+
end
|
61
|
+
|
62
|
+
# Increment a counter
|
63
|
+
# @param name [String] Counter name
|
64
|
+
# @param **labels [Hash] Counter labels
|
65
|
+
def increment_counter(name, **labels)
|
66
|
+
metrics.increment(name, **labels)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Record timing information
|
70
|
+
# @param name [String] Timer name
|
71
|
+
# @param duration [Numeric] Duration in seconds
|
72
|
+
# @param **labels [Hash] Timer labels
|
73
|
+
def record_timing(name, duration, **labels)
|
74
|
+
metrics.timing(name, duration, **labels)
|
75
|
+
end
|
76
|
+
|
77
|
+
# Time a block of code
|
78
|
+
# @param name [String] Timer name
|
79
|
+
# @param **labels [Hash] Timer labels
|
80
|
+
# @yield Block to time
|
81
|
+
# @return [Object] Block result
|
82
|
+
def time(name, **labels)
|
83
|
+
start_time = Time.now
|
84
|
+
result = yield
|
85
|
+
duration = Time.now - start_time
|
86
|
+
record_timing(name, duration, **labels)
|
87
|
+
result
|
88
|
+
rescue StandardError
|
89
|
+
duration = Time.now - start_time
|
90
|
+
record_timing(name, duration, status: "error", **labels)
|
91
|
+
raise
|
92
|
+
end
|
93
|
+
|
94
|
+
# Log with correlation ID
|
95
|
+
# @param level [Symbol] Log level
|
96
|
+
# @param message [String] Log message
|
97
|
+
# @param **context [Hash] Additional context
|
98
|
+
def log(level, message, **context)
|
99
|
+
logger.log(level, message, **context)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
##
|
104
|
+
# Metrics collection interface
|
105
|
+
#
|
106
|
+
class MetricsCollector
|
107
|
+
# Initialize metrics collector
|
108
|
+
# @param config [A2A::Configuration] Configuration instance
|
109
|
+
def initialize(config)
|
110
|
+
@config = config
|
111
|
+
@backends = []
|
112
|
+
@metrics_buffer = []
|
113
|
+
@mutex = Mutex.new
|
114
|
+
|
115
|
+
setup_backends
|
116
|
+
end
|
117
|
+
|
118
|
+
# Record a metric
|
119
|
+
# @param name [String] Metric name
|
120
|
+
# @param value [Numeric] Metric value
|
121
|
+
# @param **labels [Hash] Metric labels
|
122
|
+
def record(name, value, **labels)
|
123
|
+
metric = {
|
124
|
+
name: name,
|
125
|
+
value: value,
|
126
|
+
labels: labels,
|
127
|
+
timestamp: Time.now.to_f
|
128
|
+
}
|
129
|
+
|
130
|
+
@mutex.synchronize do
|
131
|
+
@metrics_buffer << metric
|
132
|
+
flush_if_needed
|
133
|
+
end
|
134
|
+
|
135
|
+
@backends.each { |backend| backend.record(name, value, **labels) }
|
136
|
+
end
|
137
|
+
|
138
|
+
# Increment a counter
|
139
|
+
# @param name [String] Counter name
|
140
|
+
# @param **labels [Hash] Counter labels
|
141
|
+
def increment(name, **labels)
|
142
|
+
record("#{name}_total", 1, **labels)
|
143
|
+
end
|
144
|
+
|
145
|
+
# Record timing information
|
146
|
+
# @param name [String] Timer name
|
147
|
+
# @param duration [Numeric] Duration in seconds
|
148
|
+
# @param **labels [Hash] Timer labels
|
149
|
+
def timing(name, duration, **labels)
|
150
|
+
record("#{name}_duration_seconds", duration, **labels)
|
151
|
+
end
|
152
|
+
|
153
|
+
# Add metrics backend
|
154
|
+
# @param backend [Object] Metrics backend
|
155
|
+
def add_backend(backend)
|
156
|
+
@backends << backend
|
157
|
+
end
|
158
|
+
|
159
|
+
# Get current metrics
|
160
|
+
# @return [Array<Hash>] Current metrics buffer
|
161
|
+
def current_metrics
|
162
|
+
@mutex.synchronize { @metrics_buffer.dup }
|
163
|
+
end
|
164
|
+
|
165
|
+
# Flush metrics buffer
|
166
|
+
def flush!
|
167
|
+
@mutex.synchronize do
|
168
|
+
@metrics_buffer.clear
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
private
|
173
|
+
|
174
|
+
def setup_backends
|
175
|
+
# Add Prometheus backend if available
|
176
|
+
add_backend(PrometheusBackend.new) if defined?(Prometheus)
|
177
|
+
|
178
|
+
# Add logging backend
|
179
|
+
add_backend(LoggingBackend.new(@config))
|
180
|
+
end
|
181
|
+
|
182
|
+
def flush_if_needed
|
183
|
+
return unless @metrics_buffer.size >= 100
|
184
|
+
|
185
|
+
# In a real implementation, you might want to flush to persistent storage
|
186
|
+
@config.logger&.debug("Metrics buffer size: #{@metrics_buffer.size}")
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
##
|
191
|
+
# Structured logger with correlation ID support
|
192
|
+
#
|
193
|
+
class StructuredLogger
|
194
|
+
# Initialize structured logger
|
195
|
+
# @param config [A2A::Configuration] Configuration instance
|
196
|
+
def initialize(config)
|
197
|
+
@config = config
|
198
|
+
@base_logger = config.logger
|
199
|
+
@correlation_ids = {}
|
200
|
+
end
|
201
|
+
|
202
|
+
# Log with structured format
|
203
|
+
# @param level [Symbol] Log level
|
204
|
+
# @param message [String] Log message
|
205
|
+
# @param **context [Hash] Additional context
|
206
|
+
def log(level, message, **context)
|
207
|
+
return unless @base_logger
|
208
|
+
|
209
|
+
correlation_id = current_correlation_id
|
210
|
+
|
211
|
+
structured_data = {
|
212
|
+
timestamp: Time.now.iso8601,
|
213
|
+
level: level.to_s.upcase,
|
214
|
+
message: message,
|
215
|
+
correlation_id: correlation_id,
|
216
|
+
component: "a2a-ruby"
|
217
|
+
}.merge(context)
|
218
|
+
|
219
|
+
@base_logger.send(level, structured_data.to_json)
|
220
|
+
end
|
221
|
+
|
222
|
+
# Set correlation ID for current thread
|
223
|
+
# @param id [String] Correlation ID
|
224
|
+
def set_correlation_id(id)
|
225
|
+
@correlation_ids[Thread.current.object_id] = id
|
226
|
+
end
|
227
|
+
|
228
|
+
# Get correlation ID for current thread
|
229
|
+
# @return [String] Correlation ID
|
230
|
+
def current_correlation_id
|
231
|
+
@correlation_ids[Thread.current.object_id] || generate_correlation_id
|
232
|
+
end
|
233
|
+
|
234
|
+
# Clear correlation ID for current thread
|
235
|
+
def clear_correlation_id
|
236
|
+
@correlation_ids.delete(Thread.current.object_id)
|
237
|
+
end
|
238
|
+
|
239
|
+
# Execute block with correlation ID
|
240
|
+
# @param id [String] Correlation ID
|
241
|
+
# @yield Block to execute
|
242
|
+
# @return [Object] Block result
|
243
|
+
def with_correlation_id(id)
|
244
|
+
old_id = current_correlation_id
|
245
|
+
set_correlation_id(id)
|
246
|
+
yield
|
247
|
+
ensure
|
248
|
+
if old_id
|
249
|
+
set_correlation_id(old_id)
|
250
|
+
else
|
251
|
+
clear_correlation_id
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
private
|
256
|
+
|
257
|
+
def generate_correlation_id
|
258
|
+
SecureRandom.hex(8)
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
##
|
263
|
+
# Health check system
|
264
|
+
#
|
265
|
+
class HealthChecker
|
266
|
+
# Initialize health checker
|
267
|
+
# @param config [A2A::Configuration] Configuration instance
|
268
|
+
def initialize(config)
|
269
|
+
@config = config
|
270
|
+
@checks = {}
|
271
|
+
end
|
272
|
+
|
273
|
+
# Register a health check
|
274
|
+
# @param name [Symbol] Check name
|
275
|
+
# @param check [Proc] Check procedure
|
276
|
+
def register_check(name, &check)
|
277
|
+
@checks[name] = check
|
278
|
+
end
|
279
|
+
|
280
|
+
# Run all health checks
|
281
|
+
# @return [Hash] Health check results
|
282
|
+
def check_health
|
283
|
+
results = {}
|
284
|
+
overall_status = :healthy
|
285
|
+
|
286
|
+
@checks.each do |name, check|
|
287
|
+
result = check.call
|
288
|
+
status = result[:status] || :healthy
|
289
|
+
results[name] = {
|
290
|
+
status: status,
|
291
|
+
message: result[:message],
|
292
|
+
timestamp: Time.now.iso8601
|
293
|
+
}
|
294
|
+
|
295
|
+
overall_status = :unhealthy if status == :unhealthy
|
296
|
+
rescue StandardError => e
|
297
|
+
results[name] = {
|
298
|
+
status: :error,
|
299
|
+
message: e.message,
|
300
|
+
timestamp: Time.now.iso8601
|
301
|
+
}
|
302
|
+
overall_status = :unhealthy
|
303
|
+
end
|
304
|
+
|
305
|
+
{
|
306
|
+
status: overall_status,
|
307
|
+
checks: results,
|
308
|
+
timestamp: Time.now.iso8601
|
309
|
+
}
|
310
|
+
end
|
311
|
+
|
312
|
+
# Check if system is healthy
|
313
|
+
# @return [Boolean]
|
314
|
+
def healthy?
|
315
|
+
check_health[:status] == :healthy
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
##
|
320
|
+
# Prometheus metrics backend
|
321
|
+
#
|
322
|
+
class PrometheusBackend
|
323
|
+
def initialize
|
324
|
+
@registry = Prometheus::Client.registry
|
325
|
+
@counters = {}
|
326
|
+
@histograms = {}
|
327
|
+
end
|
328
|
+
|
329
|
+
# Record metric in Prometheus
|
330
|
+
# @param name [String] Metric name
|
331
|
+
# @param value [Numeric] Metric value
|
332
|
+
# @param **labels [Hash] Metric labels
|
333
|
+
def record(name, value, **labels)
|
334
|
+
if name.end_with?("_total")
|
335
|
+
increment_counter(name, **labels)
|
336
|
+
elsif name.end_with?("_duration_seconds")
|
337
|
+
record_histogram(name, value, **labels)
|
338
|
+
else
|
339
|
+
# Generic gauge
|
340
|
+
record_gauge(name, value, **labels)
|
341
|
+
end
|
342
|
+
end
|
343
|
+
|
344
|
+
private
|
345
|
+
|
346
|
+
def increment_counter(name, **labels)
|
347
|
+
counter = @counters[name] ||= @registry.counter(
|
348
|
+
name.to_sym,
|
349
|
+
docstring: "A2A counter: #{name}",
|
350
|
+
labels: labels.keys
|
351
|
+
)
|
352
|
+
counter.increment(labels: labels)
|
353
|
+
end
|
354
|
+
|
355
|
+
def record_histogram(name, value, **labels)
|
356
|
+
histogram = @histograms[name] ||= @registry.histogram(
|
357
|
+
name.to_sym,
|
358
|
+
docstring: "A2A histogram: #{name}",
|
359
|
+
labels: labels.keys
|
360
|
+
)
|
361
|
+
histogram.observe(value, labels: labels)
|
362
|
+
end
|
363
|
+
|
364
|
+
def record_gauge(name, value, **labels)
|
365
|
+
# Prometheus gauge implementation would go here
|
366
|
+
# For now, just log it
|
367
|
+
end
|
368
|
+
end
|
369
|
+
|
370
|
+
##
|
371
|
+
# Logging metrics backend
|
372
|
+
#
|
373
|
+
class LoggingBackend
|
374
|
+
def initialize(config)
|
375
|
+
@config = config
|
376
|
+
@logger = config.logger
|
377
|
+
end
|
378
|
+
|
379
|
+
# Record metric to logs
|
380
|
+
# @param name [String] Metric name
|
381
|
+
# @param value [Numeric] Metric value
|
382
|
+
# @param **labels [Hash] Metric labels
|
383
|
+
def record(name, value, **labels)
|
384
|
+
return unless @logger
|
385
|
+
|
386
|
+
metric_data = {
|
387
|
+
metric_name: name,
|
388
|
+
metric_value: value,
|
389
|
+
metric_labels: labels,
|
390
|
+
timestamp: Time.now.iso8601
|
391
|
+
}
|
392
|
+
|
393
|
+
@logger.info("METRIC: #{metric_data.to_json}")
|
394
|
+
end
|
395
|
+
end
|
396
|
+
|
397
|
+
##
|
398
|
+
# Request/Response instrumentation
|
399
|
+
#
|
400
|
+
module Instrumentation
|
401
|
+
# Instrument A2A request
|
402
|
+
# @param request [Hash] Request data
|
403
|
+
# @yield Block to execute
|
404
|
+
# @return [Object] Block result
|
405
|
+
def self.instrument_request(request)
|
406
|
+
method = request[:method] || "unknown"
|
407
|
+
labels = { method: method }
|
408
|
+
|
409
|
+
A2A::Monitoring.increment_counter("a2a_requests", **labels)
|
410
|
+
|
411
|
+
A2A::Monitoring.time("a2a_request_duration", **labels) do
|
412
|
+
correlation_id = request[:id] || SecureRandom.hex(8)
|
413
|
+
|
414
|
+
A2A::Monitoring.logger.with_correlation_id(correlation_id) do
|
415
|
+
A2A::Monitoring.log(:info, "Processing A2A request", method: method, request_id: correlation_id)
|
416
|
+
|
417
|
+
begin
|
418
|
+
result = yield
|
419
|
+
A2A::Monitoring.increment_counter("a2a_requests_success", **labels)
|
420
|
+
A2A::Monitoring.log(:info, "A2A request completed", method: method, request_id: correlation_id)
|
421
|
+
result
|
422
|
+
rescue StandardError => e
|
423
|
+
A2A::Monitoring.increment_counter("a2a_requests_error", **labels, error_type: e.class.name)
|
424
|
+
A2A::Monitoring.log(:error, "A2A request failed", method: method, request_id: correlation_id,
|
425
|
+
error: e.message)
|
426
|
+
raise
|
427
|
+
end
|
428
|
+
end
|
429
|
+
end
|
430
|
+
end
|
431
|
+
|
432
|
+
# Instrument task operations
|
433
|
+
# @param task_id [String] Task ID
|
434
|
+
# @param operation [String] Operation name
|
435
|
+
# @yield Block to execute
|
436
|
+
# @return [Object] Block result
|
437
|
+
def self.instrument_task(task_id, operation)
|
438
|
+
labels = { operation: operation }
|
439
|
+
|
440
|
+
A2A::Monitoring.increment_counter("a2a_task_operations", **labels)
|
441
|
+
|
442
|
+
A2A::Monitoring.time("a2a_task_operation_duration", **labels) do
|
443
|
+
A2A::Monitoring.logger.with_correlation_id(task_id) do
|
444
|
+
A2A::Monitoring.log(:info, "Task operation started", task_id: task_id, operation: operation)
|
445
|
+
|
446
|
+
begin
|
447
|
+
result = yield
|
448
|
+
A2A::Monitoring.increment_counter("a2a_task_operations_success", **labels)
|
449
|
+
A2A::Monitoring.log(:info, "Task operation completed", task_id: task_id, operation: operation)
|
450
|
+
result
|
451
|
+
rescue StandardError => e
|
452
|
+
A2A::Monitoring.increment_counter("a2a_task_operations_error",
|
453
|
+
**labels, error_type: e.class.name)
|
454
|
+
A2A::Monitoring.log(:error, "Task operation failed", task_id: task_id, operation: operation,
|
455
|
+
error: e.message)
|
456
|
+
raise
|
457
|
+
end
|
458
|
+
end
|
459
|
+
end
|
460
|
+
end
|
461
|
+
end
|
462
|
+
end
|
463
|
+
end
|