rapitapir 0.1.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 +57 -0
- data/CHANGELOG.md +94 -0
- data/CLEANUP_SUMMARY.md +155 -0
- data/CONTRIBUTING.md +280 -0
- data/LICENSE +21 -0
- data/README.md +485 -0
- data/debug_hash.rb +20 -0
- data/docs/EXTENSION_COMPARISON.md +388 -0
- data/docs/SINATRA_EXTENSION.md +467 -0
- data/docs/archive/PHASE_1_2_COMPLETE.md +77 -0
- data/docs/archive/PHASE_1_3_COMPLETE.md +152 -0
- data/docs/archive/PHASE_2_1_OBSERVABILITY_COMPLETED.md +203 -0
- data/docs/archive/PHASE_2_SUMMARY.md +209 -0
- data/docs/archive/REFACTORING_SUMMARY.md +184 -0
- data/docs/archive/phase_1_3_plan.md +136 -0
- data/docs/archive/sinatra_extension_summary.md +188 -0
- data/docs/archive/sinatra_working_solution.md +113 -0
- data/docs/archive/typescript-client-generator-summary.md +259 -0
- data/docs/auto-derivation.md +146 -0
- data/docs/blueprint.md +1091 -0
- data/docs/endpoint-definition.md +211 -0
- data/docs/github_pages_fix.md +52 -0
- data/docs/github_pages_setup.md +49 -0
- data/docs/implementation-status.md +357 -0
- data/docs/observability.md +647 -0
- data/docs/phase3-plan.md +108 -0
- data/docs/sinatra_rapitapir.md +87 -0
- data/docs/type_shortcuts.md +146 -0
- data/examples/README_ENTERPRISE.md +202 -0
- data/examples/authentication_example.rb +192 -0
- data/examples/auto_derivation_ruby_friendly.rb +163 -0
- data/examples/cli/user_api_endpoints.rb +56 -0
- data/examples/client/typescript_client_example.rb +102 -0
- data/examples/client/user-api-client.ts +193 -0
- data/examples/demo_api.rb +41 -0
- data/examples/docs/documentation_example.rb +112 -0
- data/examples/docs/user-api-docs.html +789 -0
- data/examples/docs/user-api-docs.md +403 -0
- data/examples/enhanced_auto_derivation_test.rb +83 -0
- data/examples/enterprise_extension_demo.rb +417 -0
- data/examples/enterprise_rapitapir_api.rb +662 -0
- data/examples/getting_started_extension.rb +218 -0
- data/examples/hello_world.rb +74 -0
- data/examples/oauth2/.env.example +19 -0
- data/examples/oauth2/README.md +205 -0
- data/examples/oauth2/generic_oauth2_api.rb +226 -0
- data/examples/oauth2/get_token.rb +72 -0
- data/examples/oauth2/songs_api_with_auth0.rb +320 -0
- data/examples/oauth2/test_api.sh +16 -0
- data/examples/oauth2/test_songs_api.sh +110 -0
- data/examples/observability/.env.example +35 -0
- data/examples/observability/README.md +230 -0
- data/examples/observability/README_HONEYCOMB.md +332 -0
- data/examples/observability/advanced_setup.rb +384 -0
- data/examples/observability/basic_setup.rb +192 -0
- data/examples/observability/complete_test.rb +121 -0
- data/examples/observability/honeycomb_example.rb +523 -0
- data/examples/observability/honeycomb_rapitapir_clean.rb +488 -0
- data/examples/observability/honeycomb_rapitapir_example.rb +523 -0
- data/examples/observability/honeycomb_working_example.rb +489 -0
- data/examples/observability/quick_test.rb +78 -0
- data/examples/observability/simple_test.rb +14 -0
- data/examples/observability/test_honeycomb_demo.rb +354 -0
- data/examples/observability/test_live_honeycomb.rb +111 -0
- data/examples/observability/test_validation.rb +78 -0
- data/examples/observability/test_working_validation.rb +66 -0
- data/examples/openapi/user_api_schema.rb +132 -0
- data/examples/production_ready_example.rb +105 -0
- data/examples/rails/users_controller.rb +146 -0
- data/examples/readme/basic_sinatra_example.rb +128 -0
- data/examples/server/user_api.rb +179 -0
- data/examples/simple_auto_derivation_demo.rb +44 -0
- data/examples/simple_demo_api.rb +18 -0
- data/examples/sinatra/user_app.rb +127 -0
- data/examples/t_shortcut_demo.rb +59 -0
- data/examples/user_api.rb +190 -0
- data/examples/working_getting_started.rb +184 -0
- data/examples/working_simple_example.rb +195 -0
- data/lib/rapitapir/auth/configuration.rb +129 -0
- data/lib/rapitapir/auth/context.rb +122 -0
- data/lib/rapitapir/auth/errors.rb +104 -0
- data/lib/rapitapir/auth/middleware.rb +324 -0
- data/lib/rapitapir/auth/oauth2.rb +350 -0
- data/lib/rapitapir/auth/schemes.rb +420 -0
- data/lib/rapitapir/auth.rb +113 -0
- data/lib/rapitapir/cli/command.rb +535 -0
- data/lib/rapitapir/cli/server.rb +243 -0
- data/lib/rapitapir/cli/validator.rb +373 -0
- data/lib/rapitapir/client/generator_base.rb +272 -0
- data/lib/rapitapir/client/typescript_generator.rb +350 -0
- data/lib/rapitapir/core/endpoint.rb +158 -0
- data/lib/rapitapir/core/enhanced_endpoint.rb +235 -0
- data/lib/rapitapir/core/input.rb +182 -0
- data/lib/rapitapir/core/output.rb +164 -0
- data/lib/rapitapir/core/request.rb +19 -0
- data/lib/rapitapir/core/response.rb +17 -0
- data/lib/rapitapir/docs/html_generator.rb +780 -0
- data/lib/rapitapir/docs/markdown_generator.rb +464 -0
- data/lib/rapitapir/dsl/endpoint_dsl.rb +116 -0
- data/lib/rapitapir/dsl/enhanced_endpoint_dsl.rb +62 -0
- data/lib/rapitapir/dsl/enhanced_input.rb +73 -0
- data/lib/rapitapir/dsl/enhanced_output.rb +63 -0
- data/lib/rapitapir/dsl/enhanced_structures.rb +393 -0
- data/lib/rapitapir/dsl/fluent_dsl.rb +72 -0
- data/lib/rapitapir/dsl/fluent_endpoint_builder.rb +316 -0
- data/lib/rapitapir/dsl/http_verbs.rb +77 -0
- data/lib/rapitapir/dsl/input_methods.rb +47 -0
- data/lib/rapitapir/dsl/observability_methods.rb +81 -0
- data/lib/rapitapir/dsl/output_methods.rb +43 -0
- data/lib/rapitapir/dsl/type_resolution.rb +43 -0
- data/lib/rapitapir/observability/configuration.rb +108 -0
- data/lib/rapitapir/observability/health_check.rb +236 -0
- data/lib/rapitapir/observability/logging.rb +270 -0
- data/lib/rapitapir/observability/metrics.rb +203 -0
- data/lib/rapitapir/observability/middleware.rb +243 -0
- data/lib/rapitapir/observability/tracing.rb +143 -0
- data/lib/rapitapir/observability.rb +28 -0
- data/lib/rapitapir/openapi/schema_generator.rb +403 -0
- data/lib/rapitapir/schema.rb +136 -0
- data/lib/rapitapir/server/enhanced_rack_adapter.rb +379 -0
- data/lib/rapitapir/server/middleware.rb +120 -0
- data/lib/rapitapir/server/path_matcher.rb +45 -0
- data/lib/rapitapir/server/rack_adapter.rb +215 -0
- data/lib/rapitapir/server/rails_adapter.rb +17 -0
- data/lib/rapitapir/server/rails_adapter_class.rb +53 -0
- data/lib/rapitapir/server/rails_controller.rb +72 -0
- data/lib/rapitapir/server/rails_input_processor.rb +73 -0
- data/lib/rapitapir/server/rails_response_handler.rb +29 -0
- data/lib/rapitapir/server/sinatra_adapter.rb +200 -0
- data/lib/rapitapir/server/sinatra_integration.rb +93 -0
- data/lib/rapitapir/sinatra/configuration.rb +91 -0
- data/lib/rapitapir/sinatra/extension.rb +214 -0
- data/lib/rapitapir/sinatra/oauth2_helpers.rb +236 -0
- data/lib/rapitapir/sinatra/resource_builder.rb +152 -0
- data/lib/rapitapir/sinatra/swagger_ui_generator.rb +166 -0
- data/lib/rapitapir/sinatra_rapitapir.rb +40 -0
- data/lib/rapitapir/types/array.rb +163 -0
- data/lib/rapitapir/types/auto_derivation.rb +265 -0
- data/lib/rapitapir/types/base.rb +146 -0
- data/lib/rapitapir/types/boolean.rb +46 -0
- data/lib/rapitapir/types/date.rb +92 -0
- data/lib/rapitapir/types/datetime.rb +98 -0
- data/lib/rapitapir/types/email.rb +32 -0
- data/lib/rapitapir/types/float.rb +134 -0
- data/lib/rapitapir/types/hash.rb +161 -0
- data/lib/rapitapir/types/integer.rb +143 -0
- data/lib/rapitapir/types/object.rb +156 -0
- data/lib/rapitapir/types/optional.rb +65 -0
- data/lib/rapitapir/types/string.rb +185 -0
- data/lib/rapitapir/types/uuid.rb +32 -0
- data/lib/rapitapir/types.rb +155 -0
- data/lib/rapitapir/version.rb +5 -0
- data/lib/rapitapir.rb +173 -0
- data/rapitapir.gemspec +66 -0
- metadata +387 -0
@@ -0,0 +1,647 @@
|
|
1
|
+
# RapiTapir Observability Guide
|
2
|
+
|
3
|
+
This guide covers the comprehensive observability features introduced in RapiTapir Phase 2.1, including metrics collection, distributed tracing, structured logging, and health checks.
|
4
|
+
|
5
|
+
## Table of Contents
|
6
|
+
|
7
|
+
- [Quick Start](#quick-start)
|
8
|
+
- [Configuration](#configuration)
|
9
|
+
- [Metrics](#metrics)
|
10
|
+
- [Distributed Tracing](#distributed-tracing)
|
11
|
+
- [Structured Logging](#structured-logging)
|
12
|
+
- [Health Checks](#health-checks)
|
13
|
+
- [Middleware Integration](#middleware-integration)
|
14
|
+
- [Examples](#examples)
|
15
|
+
|
16
|
+
## Quick Start
|
17
|
+
|
18
|
+
```ruby
|
19
|
+
require 'rapitapir'
|
20
|
+
|
21
|
+
# Configure observability
|
22
|
+
RapiTapir.configure do |config|
|
23
|
+
# Enable Prometheus metrics
|
24
|
+
config.metrics.enable_prometheus
|
25
|
+
|
26
|
+
# Enable OpenTelemetry tracing
|
27
|
+
config.tracing.enable_opentelemetry
|
28
|
+
|
29
|
+
# Enable structured logging
|
30
|
+
config.logging.enable_structured
|
31
|
+
|
32
|
+
# Enable health checks
|
33
|
+
config.health_check.enable
|
34
|
+
end
|
35
|
+
|
36
|
+
# Create an endpoint with observability
|
37
|
+
endpoint = RapiTapir.endpoint
|
38
|
+
.get
|
39
|
+
.in("/users")
|
40
|
+
.out_json({ users: [{ id: :uuid, name: :string }] })
|
41
|
+
.with_metrics("user_list")
|
42
|
+
.with_tracing
|
43
|
+
.with_logging(level: :info)
|
44
|
+
.handle do |request|
|
45
|
+
# Your endpoint logic here
|
46
|
+
{ users: [] }
|
47
|
+
end
|
48
|
+
```
|
49
|
+
|
50
|
+
## Configuration
|
51
|
+
|
52
|
+
### Metrics Configuration
|
53
|
+
|
54
|
+
```ruby
|
55
|
+
RapiTapir.configure do |config|
|
56
|
+
config.metrics.enable_prometheus(
|
57
|
+
namespace: 'my_api', # Metrics namespace (default: 'rapitapir')
|
58
|
+
labels: { # Custom labels for all metrics
|
59
|
+
service: 'user_service',
|
60
|
+
version: '1.0.0',
|
61
|
+
environment: 'production'
|
62
|
+
}
|
63
|
+
)
|
64
|
+
end
|
65
|
+
```
|
66
|
+
|
67
|
+
### Tracing Configuration
|
68
|
+
|
69
|
+
```ruby
|
70
|
+
RapiTapir.configure do |config|
|
71
|
+
config.tracing.enable_opentelemetry(
|
72
|
+
service_name: 'my-api-service', # Service name for tracing
|
73
|
+
service_version: '1.0.0' # Service version
|
74
|
+
)
|
75
|
+
end
|
76
|
+
```
|
77
|
+
|
78
|
+
### Logging Configuration
|
79
|
+
|
80
|
+
```ruby
|
81
|
+
RapiTapir.configure do |config|
|
82
|
+
config.logging.enable_structured(
|
83
|
+
level: :info, # Log level (:debug, :info, :warn, :error, :fatal)
|
84
|
+
fields: [ # Fields to include in structured logs
|
85
|
+
:timestamp, :level, :message, :request_id,
|
86
|
+
:method, :path, :status, :duration,
|
87
|
+
:user_id, :tenant_id # Custom fields
|
88
|
+
]
|
89
|
+
)
|
90
|
+
end
|
91
|
+
```
|
92
|
+
|
93
|
+
### Health Check Configuration
|
94
|
+
|
95
|
+
```ruby
|
96
|
+
RapiTapir.configure do |config|
|
97
|
+
config.health_check.enable(endpoint: '/health')
|
98
|
+
|
99
|
+
# Add custom health checks
|
100
|
+
config.health_check.add_check(:database) do
|
101
|
+
# Database health check logic
|
102
|
+
{ status: :healthy, message: 'Database connection OK' }
|
103
|
+
end
|
104
|
+
|
105
|
+
config.health_check.add_check(:redis) do
|
106
|
+
# Redis health check logic
|
107
|
+
{ status: :healthy, message: 'Redis connection OK' }
|
108
|
+
end
|
109
|
+
end
|
110
|
+
```
|
111
|
+
|
112
|
+
## Metrics
|
113
|
+
|
114
|
+
RapiTapir automatically collects the following metrics:
|
115
|
+
|
116
|
+
### Default HTTP Metrics
|
117
|
+
|
118
|
+
- `{namespace}_http_requests_total` - Total number of HTTP requests
|
119
|
+
- `{namespace}_http_request_duration_seconds` - HTTP request duration histogram
|
120
|
+
- `{namespace}_http_errors_total` - Total number of HTTP errors
|
121
|
+
- `{namespace}_http_active_requests` - Number of active HTTP requests
|
122
|
+
|
123
|
+
### Custom Metrics
|
124
|
+
|
125
|
+
You can record custom metrics in your endpoint handlers:
|
126
|
+
|
127
|
+
```ruby
|
128
|
+
endpoint = RapiTapir.endpoint
|
129
|
+
.post
|
130
|
+
.in("/orders")
|
131
|
+
.with_metrics("order_creation")
|
132
|
+
.handle do |request|
|
133
|
+
# Custom counter
|
134
|
+
RapiTapir::Observability::Metrics.registry
|
135
|
+
.counter(:custom_events_total, labels: [:event_type])
|
136
|
+
.increment(labels: { event_type: 'order_created' })
|
137
|
+
|
138
|
+
# Custom histogram
|
139
|
+
duration = measure_time do
|
140
|
+
# Some operation
|
141
|
+
end
|
142
|
+
|
143
|
+
RapiTapir::Observability::Metrics.registry
|
144
|
+
.histogram(:operation_duration_seconds, labels: [:operation])
|
145
|
+
.observe(duration, labels: { operation: 'order_processing' })
|
146
|
+
|
147
|
+
# Your logic here
|
148
|
+
end
|
149
|
+
```
|
150
|
+
|
151
|
+
### Accessing Metrics
|
152
|
+
|
153
|
+
Metrics are exposed at `/metrics` endpoint in Prometheus format:
|
154
|
+
|
155
|
+
```bash
|
156
|
+
curl http://localhost:9292/metrics
|
157
|
+
```
|
158
|
+
|
159
|
+
## Distributed Tracing
|
160
|
+
|
161
|
+
RapiTapir integrates with OpenTelemetry for distributed tracing:
|
162
|
+
|
163
|
+
### Automatic Tracing
|
164
|
+
|
165
|
+
Every HTTP request is automatically traced with:
|
166
|
+
- Span name: `HTTP {METHOD} {PATH}`
|
167
|
+
- HTTP method, URL, status code, duration
|
168
|
+
- Request and response size
|
169
|
+
- Error information if applicable
|
170
|
+
|
171
|
+
### Custom Tracing
|
172
|
+
|
173
|
+
Add custom spans and attributes in your endpoints:
|
174
|
+
|
175
|
+
```ruby
|
176
|
+
endpoint = RapiTapir.endpoint
|
177
|
+
.post
|
178
|
+
.in("/orders")
|
179
|
+
.with_tracing("POST /orders")
|
180
|
+
.handle do |request|
|
181
|
+
# Add custom attributes to current span
|
182
|
+
RapiTapir::Observability::Tracing.set_attribute('user.id', request.user_id)
|
183
|
+
RapiTapir::Observability::Tracing.set_attribute('order.total', request.body[:total])
|
184
|
+
|
185
|
+
# Create nested spans
|
186
|
+
RapiTapir::Observability::Tracing.start_span("validate_order") do |span|
|
187
|
+
span.set_attribute('validation.type', 'business_rules')
|
188
|
+
validate_order(request.body)
|
189
|
+
end
|
190
|
+
|
191
|
+
RapiTapir::Observability::Tracing.start_span("process_payment") do |span|
|
192
|
+
payment_result = process_payment(request.body[:payment])
|
193
|
+
span.set_attribute('payment.provider', payment_result[:provider])
|
194
|
+
span.set_attribute('payment.transaction_id', payment_result[:transaction_id])
|
195
|
+
end
|
196
|
+
|
197
|
+
# Add events to span
|
198
|
+
RapiTapir::Observability::Tracing.add_event(
|
199
|
+
'order.created',
|
200
|
+
attributes: { 'order.id' => order_id }
|
201
|
+
)
|
202
|
+
|
203
|
+
# Record exceptions
|
204
|
+
begin
|
205
|
+
risky_operation()
|
206
|
+
rescue => e
|
207
|
+
RapiTapir::Observability::Tracing.record_exception(e)
|
208
|
+
raise
|
209
|
+
end
|
210
|
+
|
211
|
+
# Your logic here
|
212
|
+
end
|
213
|
+
```
|
214
|
+
|
215
|
+
## Structured Logging
|
216
|
+
|
217
|
+
RapiTapir provides comprehensive structured logging:
|
218
|
+
|
219
|
+
### Automatic Request Logging
|
220
|
+
|
221
|
+
Every HTTP request is automatically logged with:
|
222
|
+
- Request method, path, status code
|
223
|
+
- Request duration
|
224
|
+
- Request ID for correlation
|
225
|
+
- User agent, IP address
|
226
|
+
- Custom fields you configure
|
227
|
+
|
228
|
+
### Custom Logging
|
229
|
+
|
230
|
+
Add structured logging in your endpoints:
|
231
|
+
|
232
|
+
```ruby
|
233
|
+
endpoint = RapiTapir.endpoint
|
234
|
+
.post
|
235
|
+
.in("/users")
|
236
|
+
.with_logging(level: :info, fields: [:user_id, :operation])
|
237
|
+
.handle do |request|
|
238
|
+
user_data = request.body
|
239
|
+
|
240
|
+
# Structured info logging
|
241
|
+
RapiTapir::Observability::Logging.info(
|
242
|
+
"Creating user",
|
243
|
+
user_email: user_data[:email],
|
244
|
+
user_age: user_data[:age],
|
245
|
+
operation: 'user_creation'
|
246
|
+
)
|
247
|
+
|
248
|
+
# Log with different levels
|
249
|
+
RapiTapir::Observability::Logging.debug(
|
250
|
+
"Validation passed",
|
251
|
+
validation_time_ms: 5.2
|
252
|
+
)
|
253
|
+
|
254
|
+
RapiTapir::Observability::Logging.warn(
|
255
|
+
"Slow database response",
|
256
|
+
db_response_time_ms: 1200
|
257
|
+
)
|
258
|
+
|
259
|
+
# Log errors with context
|
260
|
+
begin
|
261
|
+
create_user(user_data)
|
262
|
+
rescue => e
|
263
|
+
RapiTapir::Observability::Logging.log_error(
|
264
|
+
e,
|
265
|
+
user_email: user_data[:email],
|
266
|
+
operation: 'user_creation',
|
267
|
+
request_id: request.id
|
268
|
+
)
|
269
|
+
raise
|
270
|
+
end
|
271
|
+
|
272
|
+
# Your logic here
|
273
|
+
end
|
274
|
+
```
|
275
|
+
|
276
|
+
### Log Formats
|
277
|
+
|
278
|
+
Choose from multiple log formats:
|
279
|
+
|
280
|
+
```ruby
|
281
|
+
# JSON format (default for structured logging)
|
282
|
+
{"timestamp":"2024-01-01T12:00:00Z","level":"INFO","message":"User created","user_id":"123"}
|
283
|
+
|
284
|
+
# Logfmt format
|
285
|
+
timestamp=2024-01-01T12:00:00Z level=INFO message="User created" user_id=123
|
286
|
+
|
287
|
+
# Text format
|
288
|
+
2024-01-01 12:00:00 [INFO] User created user_id=123
|
289
|
+
```
|
290
|
+
|
291
|
+
## Health Checks
|
292
|
+
|
293
|
+
RapiTapir provides comprehensive health check functionality:
|
294
|
+
|
295
|
+
### Default Health Checks
|
296
|
+
|
297
|
+
- `ruby_runtime` - Ruby runtime status
|
298
|
+
- `memory_usage` - Memory and GC statistics
|
299
|
+
- `thread_count` - Active thread count
|
300
|
+
|
301
|
+
### Custom Health Checks
|
302
|
+
|
303
|
+
Add custom health checks for your dependencies:
|
304
|
+
|
305
|
+
```ruby
|
306
|
+
RapiTapir.configure do |config|
|
307
|
+
config.health_check.enable
|
308
|
+
|
309
|
+
# Database health check
|
310
|
+
config.health_check.add_check(:database) do
|
311
|
+
begin
|
312
|
+
result = ActiveRecord::Base.connection.execute("SELECT 1")
|
313
|
+
{ status: :healthy, message: "Database connection OK" }
|
314
|
+
rescue => e
|
315
|
+
{ status: :unhealthy, message: "Database error: #{e.message}" }
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
# Redis health check with timeout
|
320
|
+
config.health_check.add_check(:redis) do
|
321
|
+
begin
|
322
|
+
Timeout.timeout(5) do
|
323
|
+
Redis.current.ping
|
324
|
+
{ status: :healthy, message: "Redis connection OK" }
|
325
|
+
end
|
326
|
+
rescue Timeout::Error
|
327
|
+
{ status: :unhealthy, message: "Redis timeout" }
|
328
|
+
rescue => e
|
329
|
+
{ status: :unhealthy, message: "Redis error: #{e.message}" }
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
# External API health check
|
334
|
+
config.health_check.add_check(:payment_api) do
|
335
|
+
begin
|
336
|
+
response = HTTP.timeout(10).get("https://api.stripe.com/v1/charges")
|
337
|
+
if response.status.success?
|
338
|
+
{ status: :healthy, message: "Payment API reachable" }
|
339
|
+
else
|
340
|
+
{ status: :unhealthy, message: "Payment API returned #{response.status}" }
|
341
|
+
end
|
342
|
+
rescue => e
|
343
|
+
{ status: :unhealthy, message: "Payment API unreachable: #{e.message}" }
|
344
|
+
end
|
345
|
+
end
|
346
|
+
end
|
347
|
+
```
|
348
|
+
|
349
|
+
### Health Check Endpoints
|
350
|
+
|
351
|
+
Health checks are available at multiple endpoints:
|
352
|
+
|
353
|
+
```bash
|
354
|
+
# Overall health status
|
355
|
+
GET /health
|
356
|
+
{
|
357
|
+
"status": "healthy",
|
358
|
+
"timestamp": "2024-01-01T12:00:00Z",
|
359
|
+
"service": "rapitapir",
|
360
|
+
"version": "0.1.0",
|
361
|
+
"checks": [
|
362
|
+
{
|
363
|
+
"name": "database",
|
364
|
+
"status": "healthy",
|
365
|
+
"message": "Database connection OK",
|
366
|
+
"duration_ms": 2.5
|
367
|
+
}
|
368
|
+
]
|
369
|
+
}
|
370
|
+
|
371
|
+
# Individual health check
|
372
|
+
GET /health/check?name=database
|
373
|
+
{
|
374
|
+
"name": "database",
|
375
|
+
"status": "healthy",
|
376
|
+
"message": "Database connection OK",
|
377
|
+
"duration_ms": 2.5
|
378
|
+
}
|
379
|
+
|
380
|
+
# List available checks
|
381
|
+
GET /health/checks
|
382
|
+
{
|
383
|
+
"available_checks": [
|
384
|
+
{"name": "ruby_runtime", "url": "/health/check?name=ruby_runtime"},
|
385
|
+
{"name": "database", "url": "/health/check?name=database"}
|
386
|
+
],
|
387
|
+
"total": 2
|
388
|
+
}
|
389
|
+
```
|
390
|
+
|
391
|
+
## Middleware Integration
|
392
|
+
|
393
|
+
### Rack Applications
|
394
|
+
|
395
|
+
Use the observability middleware with any Rack application:
|
396
|
+
|
397
|
+
```ruby
|
398
|
+
require 'rack'
|
399
|
+
require 'rapitapir'
|
400
|
+
|
401
|
+
# Configure observability
|
402
|
+
RapiTapir.configure do |config|
|
403
|
+
config.metrics.enable_prometheus
|
404
|
+
config.tracing.enable_opentelemetry
|
405
|
+
config.logging.enable_structured
|
406
|
+
config.health_check.enable
|
407
|
+
end
|
408
|
+
|
409
|
+
# Build application with observability
|
410
|
+
app = Rack::Builder.new do
|
411
|
+
# Add observability middleware (includes metrics, tracing, logging)
|
412
|
+
use RapiTapir::Observability::RackMiddleware
|
413
|
+
|
414
|
+
# Your application
|
415
|
+
run MyApp.new
|
416
|
+
end
|
417
|
+
|
418
|
+
run app
|
419
|
+
```
|
420
|
+
|
421
|
+
### Sinatra Integration
|
422
|
+
|
423
|
+
```ruby
|
424
|
+
require 'sinatra'
|
425
|
+
require 'rapitapir'
|
426
|
+
|
427
|
+
# Configure observability
|
428
|
+
RapiTapir.configure do |config|
|
429
|
+
config.metrics.enable_prometheus
|
430
|
+
config.tracing.enable_opentelemetry
|
431
|
+
config.logging.enable_structured
|
432
|
+
config.health_check.enable
|
433
|
+
end
|
434
|
+
|
435
|
+
class MyApp < Sinatra::Base
|
436
|
+
use RapiTapir::Observability::RackMiddleware
|
437
|
+
|
438
|
+
get '/users' do
|
439
|
+
# Your route logic
|
440
|
+
end
|
441
|
+
end
|
442
|
+
```
|
443
|
+
|
444
|
+
### Rails Integration
|
445
|
+
|
446
|
+
```ruby
|
447
|
+
# config/application.rb
|
448
|
+
require 'rapitapir'
|
449
|
+
|
450
|
+
class Application < Rails::Application
|
451
|
+
# Configure observability
|
452
|
+
config.before_configuration do
|
453
|
+
RapiTapir.configure do |config|
|
454
|
+
config.metrics.enable_prometheus(
|
455
|
+
namespace: 'rails_app',
|
456
|
+
labels: { environment: Rails.env }
|
457
|
+
)
|
458
|
+
config.tracing.enable_opentelemetry(
|
459
|
+
service_name: 'my-rails-app',
|
460
|
+
service_version: MyApp::VERSION
|
461
|
+
)
|
462
|
+
config.logging.enable_structured(level: :info)
|
463
|
+
config.health_check.enable
|
464
|
+
end
|
465
|
+
end
|
466
|
+
|
467
|
+
# Add observability middleware
|
468
|
+
config.middleware.use RapiTapir::Observability::RackMiddleware
|
469
|
+
end
|
470
|
+
```
|
471
|
+
|
472
|
+
## Examples
|
473
|
+
|
474
|
+
### Basic E-commerce API
|
475
|
+
|
476
|
+
```ruby
|
477
|
+
require 'rapitapir'
|
478
|
+
|
479
|
+
# Configure observability
|
480
|
+
RapiTapir.configure do |config|
|
481
|
+
config.metrics.enable_prometheus(namespace: 'ecommerce')
|
482
|
+
config.tracing.enable_opentelemetry(service_name: 'ecommerce-api')
|
483
|
+
config.logging.enable_structured
|
484
|
+
config.health_check.enable
|
485
|
+
end
|
486
|
+
|
487
|
+
# Create order endpoint
|
488
|
+
create_order = RapiTapir.endpoint
|
489
|
+
.post
|
490
|
+
.in("/orders")
|
491
|
+
.json_body({
|
492
|
+
customer_id: :uuid,
|
493
|
+
items: [{ product_id: :uuid, quantity: :integer, price: :float }]
|
494
|
+
})
|
495
|
+
.out_json({ id: :uuid, status: :string, total: :float })
|
496
|
+
.with_metrics("order_creation")
|
497
|
+
.with_tracing
|
498
|
+
.with_logging(fields: [:customer_id, :order_total, :item_count])
|
499
|
+
.handle do |request|
|
500
|
+
order_data = request.body
|
501
|
+
|
502
|
+
# Add business context to tracing
|
503
|
+
RapiTapir::Observability::Tracing.set_attribute('customer.id', order_data[:customer_id])
|
504
|
+
RapiTapir::Observability::Tracing.set_attribute('order.item_count', order_data[:items].length)
|
505
|
+
|
506
|
+
total = order_data[:items].sum { |item| item[:quantity] * item[:price] }
|
507
|
+
RapiTapir::Observability::Tracing.set_attribute('order.total', total)
|
508
|
+
|
509
|
+
# Structured logging
|
510
|
+
RapiTapir::Observability::Logging.info(
|
511
|
+
"Processing order",
|
512
|
+
customer_id: order_data[:customer_id],
|
513
|
+
order_total: total,
|
514
|
+
item_count: order_data[:items].length
|
515
|
+
)
|
516
|
+
|
517
|
+
# Process order with nested tracing
|
518
|
+
order_id = RapiTapir::Observability::Tracing.start_span("create_order_record") do
|
519
|
+
SecureRandom.uuid
|
520
|
+
end
|
521
|
+
|
522
|
+
RapiTapir::Observability::Tracing.start_span("send_confirmation_email") do |span|
|
523
|
+
span.set_attribute('email.type', 'order_confirmation')
|
524
|
+
# Send confirmation email
|
525
|
+
end
|
526
|
+
|
527
|
+
{
|
528
|
+
id: order_id,
|
529
|
+
status: 'confirmed',
|
530
|
+
total: total
|
531
|
+
}
|
532
|
+
end
|
533
|
+
```
|
534
|
+
|
535
|
+
### Advanced Monitoring Setup
|
536
|
+
|
537
|
+
```ruby
|
538
|
+
# Production observability configuration
|
539
|
+
RapiTapir.configure do |config|
|
540
|
+
# Comprehensive metrics
|
541
|
+
config.metrics.enable_prometheus(
|
542
|
+
namespace: 'production_api',
|
543
|
+
labels: {
|
544
|
+
service: ENV['SERVICE_NAME'],
|
545
|
+
version: ENV['APP_VERSION'],
|
546
|
+
environment: ENV['RAILS_ENV'],
|
547
|
+
datacenter: ENV['DATACENTER']
|
548
|
+
}
|
549
|
+
)
|
550
|
+
|
551
|
+
# Distributed tracing
|
552
|
+
config.tracing.enable_opentelemetry(
|
553
|
+
service_name: ENV['SERVICE_NAME'],
|
554
|
+
service_version: ENV['APP_VERSION']
|
555
|
+
)
|
556
|
+
|
557
|
+
# Structured logging for log aggregation
|
558
|
+
config.logging.enable_structured(
|
559
|
+
level: ENV.fetch('LOG_LEVEL', 'info').to_sym,
|
560
|
+
fields: [
|
561
|
+
:timestamp, :level, :message, :request_id, :trace_id,
|
562
|
+
:method, :path, :status, :duration,
|
563
|
+
:user_id, :tenant_id, :session_id,
|
564
|
+
:source_ip, :user_agent
|
565
|
+
]
|
566
|
+
)
|
567
|
+
|
568
|
+
# Comprehensive health checks
|
569
|
+
config.health_check.enable(endpoint: '/health')
|
570
|
+
|
571
|
+
# Database health check
|
572
|
+
config.health_check.add_check(:database) do
|
573
|
+
ActiveRecord::Base.connection.execute("SELECT 1")
|
574
|
+
{ status: :healthy, message: "Primary database OK" }
|
575
|
+
rescue => e
|
576
|
+
{ status: :unhealthy, message: "Database error: #{e.message}" }
|
577
|
+
end
|
578
|
+
|
579
|
+
# Redis health check
|
580
|
+
config.health_check.add_check(:redis) do
|
581
|
+
Redis.current.ping
|
582
|
+
{ status: :healthy, message: "Redis cache OK" }
|
583
|
+
rescue => e
|
584
|
+
{ status: :unhealthy, message: "Redis error: #{e.message}" }
|
585
|
+
end
|
586
|
+
|
587
|
+
# Message queue health check
|
588
|
+
config.health_check.add_check(:message_queue) do
|
589
|
+
# Check Sidekiq or similar
|
590
|
+
if defined?(Sidekiq)
|
591
|
+
stats = Sidekiq::Stats.new
|
592
|
+
queue_size = stats.enqueued
|
593
|
+
|
594
|
+
if queue_size > 10000
|
595
|
+
{ status: :warning, message: "High queue size: #{queue_size}" }
|
596
|
+
else
|
597
|
+
{ status: :healthy, message: "Queue size: #{queue_size}" }
|
598
|
+
end
|
599
|
+
else
|
600
|
+
{ status: :healthy, message: "No message queue configured" }
|
601
|
+
end
|
602
|
+
rescue => e
|
603
|
+
{ status: :unhealthy, message: "Queue error: #{e.message}" }
|
604
|
+
end
|
605
|
+
end
|
606
|
+
```
|
607
|
+
|
608
|
+
## Best Practices
|
609
|
+
|
610
|
+
### 1. Metric Naming
|
611
|
+
|
612
|
+
Use consistent metric naming:
|
613
|
+
- Use underscores for separating words
|
614
|
+
- Include units in metric names (e.g., `_seconds`, `_bytes`)
|
615
|
+
- Use clear, descriptive names
|
616
|
+
|
617
|
+
### 2. Trace Context
|
618
|
+
|
619
|
+
Add meaningful attributes to traces:
|
620
|
+
- Business identifiers (user_id, order_id, etc.)
|
621
|
+
- Request context (tenant_id, api_version)
|
622
|
+
- Performance indicators (cache_hit, db_query_count)
|
623
|
+
|
624
|
+
### 3. Structured Logging
|
625
|
+
|
626
|
+
Design your log structure:
|
627
|
+
- Use consistent field names across services
|
628
|
+
- Include correlation IDs for request tracing
|
629
|
+
- Log at appropriate levels (debug for development, info+ for production)
|
630
|
+
|
631
|
+
### 4. Health Check Design
|
632
|
+
|
633
|
+
Create meaningful health checks:
|
634
|
+
- Test actual functionality, not just connectivity
|
635
|
+
- Include response time thresholds
|
636
|
+
- Use timeouts to prevent hanging checks
|
637
|
+
- Return actionable status messages
|
638
|
+
|
639
|
+
### 5. Error Handling
|
640
|
+
|
641
|
+
Implement comprehensive error observability:
|
642
|
+
- Always record exceptions in traces
|
643
|
+
- Log errors with sufficient context
|
644
|
+
- Use error metrics to track error rates
|
645
|
+
- Include error classification (validation, system, external)
|
646
|
+
|
647
|
+
This observability implementation provides production-ready monitoring capabilities for RapiTapir applications, enabling comprehensive visibility into system performance, health, and behavior.
|