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.
Files changed (157) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/.rubocop.yml +57 -0
  4. data/CHANGELOG.md +94 -0
  5. data/CLEANUP_SUMMARY.md +155 -0
  6. data/CONTRIBUTING.md +280 -0
  7. data/LICENSE +21 -0
  8. data/README.md +485 -0
  9. data/debug_hash.rb +20 -0
  10. data/docs/EXTENSION_COMPARISON.md +388 -0
  11. data/docs/SINATRA_EXTENSION.md +467 -0
  12. data/docs/archive/PHASE_1_2_COMPLETE.md +77 -0
  13. data/docs/archive/PHASE_1_3_COMPLETE.md +152 -0
  14. data/docs/archive/PHASE_2_1_OBSERVABILITY_COMPLETED.md +203 -0
  15. data/docs/archive/PHASE_2_SUMMARY.md +209 -0
  16. data/docs/archive/REFACTORING_SUMMARY.md +184 -0
  17. data/docs/archive/phase_1_3_plan.md +136 -0
  18. data/docs/archive/sinatra_extension_summary.md +188 -0
  19. data/docs/archive/sinatra_working_solution.md +113 -0
  20. data/docs/archive/typescript-client-generator-summary.md +259 -0
  21. data/docs/auto-derivation.md +146 -0
  22. data/docs/blueprint.md +1091 -0
  23. data/docs/endpoint-definition.md +211 -0
  24. data/docs/github_pages_fix.md +52 -0
  25. data/docs/github_pages_setup.md +49 -0
  26. data/docs/implementation-status.md +357 -0
  27. data/docs/observability.md +647 -0
  28. data/docs/phase3-plan.md +108 -0
  29. data/docs/sinatra_rapitapir.md +87 -0
  30. data/docs/type_shortcuts.md +146 -0
  31. data/examples/README_ENTERPRISE.md +202 -0
  32. data/examples/authentication_example.rb +192 -0
  33. data/examples/auto_derivation_ruby_friendly.rb +163 -0
  34. data/examples/cli/user_api_endpoints.rb +56 -0
  35. data/examples/client/typescript_client_example.rb +102 -0
  36. data/examples/client/user-api-client.ts +193 -0
  37. data/examples/demo_api.rb +41 -0
  38. data/examples/docs/documentation_example.rb +112 -0
  39. data/examples/docs/user-api-docs.html +789 -0
  40. data/examples/docs/user-api-docs.md +403 -0
  41. data/examples/enhanced_auto_derivation_test.rb +83 -0
  42. data/examples/enterprise_extension_demo.rb +417 -0
  43. data/examples/enterprise_rapitapir_api.rb +662 -0
  44. data/examples/getting_started_extension.rb +218 -0
  45. data/examples/hello_world.rb +74 -0
  46. data/examples/oauth2/.env.example +19 -0
  47. data/examples/oauth2/README.md +205 -0
  48. data/examples/oauth2/generic_oauth2_api.rb +226 -0
  49. data/examples/oauth2/get_token.rb +72 -0
  50. data/examples/oauth2/songs_api_with_auth0.rb +320 -0
  51. data/examples/oauth2/test_api.sh +16 -0
  52. data/examples/oauth2/test_songs_api.sh +110 -0
  53. data/examples/observability/.env.example +35 -0
  54. data/examples/observability/README.md +230 -0
  55. data/examples/observability/README_HONEYCOMB.md +332 -0
  56. data/examples/observability/advanced_setup.rb +384 -0
  57. data/examples/observability/basic_setup.rb +192 -0
  58. data/examples/observability/complete_test.rb +121 -0
  59. data/examples/observability/honeycomb_example.rb +523 -0
  60. data/examples/observability/honeycomb_rapitapir_clean.rb +488 -0
  61. data/examples/observability/honeycomb_rapitapir_example.rb +523 -0
  62. data/examples/observability/honeycomb_working_example.rb +489 -0
  63. data/examples/observability/quick_test.rb +78 -0
  64. data/examples/observability/simple_test.rb +14 -0
  65. data/examples/observability/test_honeycomb_demo.rb +354 -0
  66. data/examples/observability/test_live_honeycomb.rb +111 -0
  67. data/examples/observability/test_validation.rb +78 -0
  68. data/examples/observability/test_working_validation.rb +66 -0
  69. data/examples/openapi/user_api_schema.rb +132 -0
  70. data/examples/production_ready_example.rb +105 -0
  71. data/examples/rails/users_controller.rb +146 -0
  72. data/examples/readme/basic_sinatra_example.rb +128 -0
  73. data/examples/server/user_api.rb +179 -0
  74. data/examples/simple_auto_derivation_demo.rb +44 -0
  75. data/examples/simple_demo_api.rb +18 -0
  76. data/examples/sinatra/user_app.rb +127 -0
  77. data/examples/t_shortcut_demo.rb +59 -0
  78. data/examples/user_api.rb +190 -0
  79. data/examples/working_getting_started.rb +184 -0
  80. data/examples/working_simple_example.rb +195 -0
  81. data/lib/rapitapir/auth/configuration.rb +129 -0
  82. data/lib/rapitapir/auth/context.rb +122 -0
  83. data/lib/rapitapir/auth/errors.rb +104 -0
  84. data/lib/rapitapir/auth/middleware.rb +324 -0
  85. data/lib/rapitapir/auth/oauth2.rb +350 -0
  86. data/lib/rapitapir/auth/schemes.rb +420 -0
  87. data/lib/rapitapir/auth.rb +113 -0
  88. data/lib/rapitapir/cli/command.rb +535 -0
  89. data/lib/rapitapir/cli/server.rb +243 -0
  90. data/lib/rapitapir/cli/validator.rb +373 -0
  91. data/lib/rapitapir/client/generator_base.rb +272 -0
  92. data/lib/rapitapir/client/typescript_generator.rb +350 -0
  93. data/lib/rapitapir/core/endpoint.rb +158 -0
  94. data/lib/rapitapir/core/enhanced_endpoint.rb +235 -0
  95. data/lib/rapitapir/core/input.rb +182 -0
  96. data/lib/rapitapir/core/output.rb +164 -0
  97. data/lib/rapitapir/core/request.rb +19 -0
  98. data/lib/rapitapir/core/response.rb +17 -0
  99. data/lib/rapitapir/docs/html_generator.rb +780 -0
  100. data/lib/rapitapir/docs/markdown_generator.rb +464 -0
  101. data/lib/rapitapir/dsl/endpoint_dsl.rb +116 -0
  102. data/lib/rapitapir/dsl/enhanced_endpoint_dsl.rb +62 -0
  103. data/lib/rapitapir/dsl/enhanced_input.rb +73 -0
  104. data/lib/rapitapir/dsl/enhanced_output.rb +63 -0
  105. data/lib/rapitapir/dsl/enhanced_structures.rb +393 -0
  106. data/lib/rapitapir/dsl/fluent_dsl.rb +72 -0
  107. data/lib/rapitapir/dsl/fluent_endpoint_builder.rb +316 -0
  108. data/lib/rapitapir/dsl/http_verbs.rb +77 -0
  109. data/lib/rapitapir/dsl/input_methods.rb +47 -0
  110. data/lib/rapitapir/dsl/observability_methods.rb +81 -0
  111. data/lib/rapitapir/dsl/output_methods.rb +43 -0
  112. data/lib/rapitapir/dsl/type_resolution.rb +43 -0
  113. data/lib/rapitapir/observability/configuration.rb +108 -0
  114. data/lib/rapitapir/observability/health_check.rb +236 -0
  115. data/lib/rapitapir/observability/logging.rb +270 -0
  116. data/lib/rapitapir/observability/metrics.rb +203 -0
  117. data/lib/rapitapir/observability/middleware.rb +243 -0
  118. data/lib/rapitapir/observability/tracing.rb +143 -0
  119. data/lib/rapitapir/observability.rb +28 -0
  120. data/lib/rapitapir/openapi/schema_generator.rb +403 -0
  121. data/lib/rapitapir/schema.rb +136 -0
  122. data/lib/rapitapir/server/enhanced_rack_adapter.rb +379 -0
  123. data/lib/rapitapir/server/middleware.rb +120 -0
  124. data/lib/rapitapir/server/path_matcher.rb +45 -0
  125. data/lib/rapitapir/server/rack_adapter.rb +215 -0
  126. data/lib/rapitapir/server/rails_adapter.rb +17 -0
  127. data/lib/rapitapir/server/rails_adapter_class.rb +53 -0
  128. data/lib/rapitapir/server/rails_controller.rb +72 -0
  129. data/lib/rapitapir/server/rails_input_processor.rb +73 -0
  130. data/lib/rapitapir/server/rails_response_handler.rb +29 -0
  131. data/lib/rapitapir/server/sinatra_adapter.rb +200 -0
  132. data/lib/rapitapir/server/sinatra_integration.rb +93 -0
  133. data/lib/rapitapir/sinatra/configuration.rb +91 -0
  134. data/lib/rapitapir/sinatra/extension.rb +214 -0
  135. data/lib/rapitapir/sinatra/oauth2_helpers.rb +236 -0
  136. data/lib/rapitapir/sinatra/resource_builder.rb +152 -0
  137. data/lib/rapitapir/sinatra/swagger_ui_generator.rb +166 -0
  138. data/lib/rapitapir/sinatra_rapitapir.rb +40 -0
  139. data/lib/rapitapir/types/array.rb +163 -0
  140. data/lib/rapitapir/types/auto_derivation.rb +265 -0
  141. data/lib/rapitapir/types/base.rb +146 -0
  142. data/lib/rapitapir/types/boolean.rb +46 -0
  143. data/lib/rapitapir/types/date.rb +92 -0
  144. data/lib/rapitapir/types/datetime.rb +98 -0
  145. data/lib/rapitapir/types/email.rb +32 -0
  146. data/lib/rapitapir/types/float.rb +134 -0
  147. data/lib/rapitapir/types/hash.rb +161 -0
  148. data/lib/rapitapir/types/integer.rb +143 -0
  149. data/lib/rapitapir/types/object.rb +156 -0
  150. data/lib/rapitapir/types/optional.rb +65 -0
  151. data/lib/rapitapir/types/string.rb +185 -0
  152. data/lib/rapitapir/types/uuid.rb +32 -0
  153. data/lib/rapitapir/types.rb +155 -0
  154. data/lib/rapitapir/version.rb +5 -0
  155. data/lib/rapitapir.rb +173 -0
  156. data/rapitapir.gemspec +66 -0
  157. metadata +387 -0
@@ -0,0 +1,110 @@
1
+ #!/bin/bash
2
+
3
+ # Test script for Songs API with Auth0
4
+ echo "🎡 Testing Songs API with Auth0 OAuth2..."
5
+
6
+ # Colors for output
7
+ RED='\033[0;31m'
8
+ GREEN='\033[0;32m'
9
+ YELLOW='\033[1;33m'
10
+ NC='\033[0m' # No Color
11
+
12
+ # Get a fresh token
13
+ echo "πŸ”‘ Getting Auth0 token..."
14
+ TOKEN=$(ruby get_token.rb 2>/dev/null | grep "πŸ“‹ Full token:" -A1 | tail -1)
15
+
16
+ if [ -z "$TOKEN" ]; then
17
+ echo -e "${RED}❌ Failed to get token${NC}"
18
+ exit 1
19
+ fi
20
+
21
+ echo -e "${GREEN}βœ… Token obtained${NC}"
22
+
23
+ # Test 1: Public endpoint (should work without auth)
24
+ echo
25
+ echo "πŸ§ͺ Test 1: GET /songs (public endpoint)"
26
+ RESPONSE=$(curl -s -w "%{http_code}" http://localhost:4567/songs)
27
+ HTTP_CODE=${RESPONSE: -3}
28
+ BODY=${RESPONSE%???}
29
+
30
+ if [ "$HTTP_CODE" = "200" ]; then
31
+ echo -e "${GREEN}βœ… Public endpoint accessible${NC}"
32
+ echo "πŸ“‹ Response: $BODY"
33
+ else
34
+ echo -e "${RED}❌ Public endpoint failed (HTTP $HTTP_CODE)${NC}"
35
+ echo "πŸ“‹ Response: $BODY"
36
+ fi
37
+
38
+ # Test 2: Protected endpoint without auth (should fail)
39
+ echo
40
+ echo "πŸ§ͺ Test 2: POST /songs without authentication"
41
+ RESPONSE=$(curl -s -w "%{http_code}" -X POST http://localhost:4567/songs \
42
+ -H "Content-Type: application/json" \
43
+ -d '{"name":"Test Song","url":"https://example.com/test"}')
44
+ HTTP_CODE=${RESPONSE: -3}
45
+ BODY=${RESPONSE%???}
46
+
47
+ if [ "$HTTP_CODE" = "401" ]; then
48
+ echo -e "${GREEN}βœ… Authentication required (as expected)${NC}"
49
+ echo "πŸ“‹ Response: $BODY"
50
+ else
51
+ echo -e "${RED}❌ Should require authentication (HTTP $HTTP_CODE)${NC}"
52
+ echo "πŸ“‹ Response: $BODY"
53
+ fi
54
+
55
+ # Test 3: Protected endpoint with valid token (should work)
56
+ echo
57
+ echo "πŸ§ͺ Test 3: POST /songs with valid Auth0 token"
58
+ RESPONSE=$(curl -s -w "%{http_code}" -X POST http://localhost:4567/songs \
59
+ -H "Content-Type: application/json" \
60
+ -H "Authorization: Bearer $TOKEN" \
61
+ -d '{"name":"Test Song from API","url":"https://example.com/test-api"}')
62
+ HTTP_CODE=${RESPONSE: -3}
63
+ BODY=${RESPONSE%???}
64
+
65
+ if [ "$HTTP_CODE" = "200" ] || [ "$HTTP_CODE" = "201" ]; then
66
+ echo -e "${GREEN}βœ… Song created successfully${NC}"
67
+ echo "πŸ“‹ Response: $BODY"
68
+ else
69
+ echo -e "${RED}❌ Song creation failed (HTTP $HTTP_CODE)${NC}"
70
+ echo "πŸ“‹ Response: $BODY"
71
+ fi
72
+
73
+ # Test 4: Verify the song was added
74
+ echo
75
+ echo "πŸ§ͺ Test 4: GET /songs (verify new song added)"
76
+ RESPONSE=$(curl -s -w "%{http_code}" http://localhost:4567/songs)
77
+ HTTP_CODE=${RESPONSE: -3}
78
+ BODY=${RESPONSE%???}
79
+
80
+ if [ "$HTTP_CODE" = "200" ]; then
81
+ echo -e "${GREEN}βœ… Songs list retrieved${NC}"
82
+ echo "πŸ“‹ Response: $BODY"
83
+
84
+ # Check if our test song appears in the list
85
+ if [[ $BODY == *"Test Song from API"* ]]; then
86
+ echo -e "${GREEN}πŸŽ‰ Test song found in the list!${NC}"
87
+ else
88
+ echo -e "${YELLOW}⚠️ Test song not found in the list${NC}"
89
+ fi
90
+ else
91
+ echo -e "${RED}❌ Failed to retrieve songs list (HTTP $HTTP_CODE)${NC}"
92
+ fi
93
+
94
+ # Test 5: Test /me endpoint
95
+ echo
96
+ echo "πŸ§ͺ Test 5: GET /me (user info with token)"
97
+ RESPONSE=$(curl -s -w "%{http_code}" -H "Authorization: Bearer $TOKEN" http://localhost:4567/me)
98
+ HTTP_CODE=${RESPONSE: -3}
99
+ BODY=${RESPONSE%???}
100
+
101
+ if [ "$HTTP_CODE" = "200" ]; then
102
+ echo -e "${GREEN}βœ… User info retrieved${NC}"
103
+ echo "πŸ“‹ Response: $BODY"
104
+ else
105
+ echo -e "${RED}❌ User info failed (HTTP $HTTP_CODE)${NC}"
106
+ echo "πŸ“‹ Response: $BODY"
107
+ fi
108
+
109
+ echo
110
+ echo "🎡 Songs API testing complete!"
@@ -0,0 +1,35 @@
1
+ # Honeycomb.io Configuration for RapiTapir Demo
2
+ # Copy this file to .env and update with your actual Honeycomb API key
3
+
4
+ # Required: Your Honeycomb API key (get from https://ui.honeycomb.io/account)
5
+ # Replace 'your-honeycomb-api-key-here' with your actual API key
6
+ OTEL_EXPORTER_OTLP_HEADERS=x-honeycomb-team=your-honeycomb-api-key-here
7
+
8
+ # Honeycomb endpoint (US instance - change to EU if needed)
9
+ OTEL_EXPORTER_OTLP_ENDPOINT=https://api.honeycomb.io
10
+
11
+ # For EU instance, uncomment the line below instead:
12
+ # OTEL_EXPORTER_OTLP_ENDPOINT=https://api.eu1.honeycomb.io
13
+
14
+ # Service configuration
15
+ OTEL_SERVICE_NAME=rapitapir-demo
16
+ OTEL_SERVICE_VERSION=1.0.0
17
+
18
+ # Resource attributes (optional but recommended)
19
+ OTEL_RESOURCE_ATTRIBUTES=service.name=rapitapir-demo,service.version=1.0.0,deployment.environment=development
20
+
21
+ # Sampling configuration (optional - keep 100% for demo, adjust for production)
22
+ # OTEL_TRACES_SAMPLER=traceidratio
23
+ # OTEL_TRACES_SAMPLER_ARG=0.1
24
+ # OTEL_RESOURCE_ATTRIBUTES=SampleRate=10
25
+
26
+ # Logging level for OpenTelemetry (optional)
27
+ OTEL_LOG_LEVEL=info
28
+
29
+ # Enable/disable specific signals (optional)
30
+ OTEL_TRACES_EXPORTER=otlp
31
+ OTEL_METRICS_EXPORTER=otlp
32
+ OTEL_LOGS_EXPORTER=otlp
33
+
34
+ # Additional debugging (optional - set to true for troubleshooting)
35
+ OTEL_RUBY_TRACES_EXPORTER_DEBUG=false
@@ -0,0 +1,230 @@
1
+ # RapiTapir Honeycomb.io Observability Example
2
+
3
+ This example demonstrates how to integrate Honeycomb.io observability with a Ruby API using OpenTelemetry and RapiTapir patterns.
4
+
5
+ ## Prerequisites
6
+
7
+ 1. **Honeycomb.io Account**: Sign up at [honeycomb.io](https://honeycomb.io)
8
+ 2. **API Key**: Get your API key from Honeycomb settings
9
+ 3. **Ruby 3.1+**: Ensure you have Ruby installed
10
+ 4. **Bundler**: For managing dependencies
11
+
12
+ ## Setup
13
+
14
+ ### 1. Install Dependencies
15
+
16
+ From the project root directory:
17
+
18
+ ```bash
19
+ cd /path/to/ruby-tapir
20
+ bundle install
21
+ ```
22
+
23
+ ### 2. Configure Environment
24
+
25
+ Create a `.env` file in the `examples/observability/` directory:
26
+
27
+ ```bash
28
+ # Honeycomb.io Configuration
29
+ HONEYCOMB_API_KEY=your_api_key_here
30
+ OTEL_EXPORTER_OTLP_ENDPOINT=https://api.honeycomb.io
31
+ OTEL_EXPORTER_OTLP_HEADERS=x-honeycomb-team=your_api_key_here
32
+ OTEL_SERVICE_NAME=rapitapir-demo
33
+ OTEL_RESOURCE_ATTRIBUTES=service.name=rapitapir-demo,service.version=1.0.0
34
+ ```
35
+
36
+ Replace `your_api_key_here` with your actual Honeycomb API key.
37
+
38
+ ### 3. Run the Server
39
+
40
+ From the project root directory:
41
+
42
+ ```bash
43
+ bundle exec ruby examples/observability/honeycomb_working_example.rb
44
+ ```
45
+
46
+ The server will start on `http://localhost:4567` and display available endpoints.
47
+
48
+ ## API Endpoints
49
+
50
+ ### Health Check
51
+ ```bash
52
+ curl http://localhost:4567/health
53
+ ```
54
+
55
+ ### User Management
56
+ ```bash
57
+ # List users (with pagination and filtering)
58
+ curl "http://localhost:4567/users?page=1&limit=10&department=engineering"
59
+
60
+ # Create user
61
+ curl -X POST http://localhost:4567/users \
62
+ -H 'Content-Type: application/json' \
63
+ -d '{"name":"Alice Johnson","email":"alice@example.com","age":28,"department":"engineering"}'
64
+
65
+ # Get user by ID
66
+ curl http://localhost:4567/users/USER_ID
67
+
68
+ # Update user
69
+ curl -X PUT http://localhost:4567/users/USER_ID \
70
+ -H 'Content-Type: application/json' \
71
+ -d '{"name":"Alice Johnson-Smith","department":"product"}'
72
+
73
+ # Delete user
74
+ curl -X DELETE http://localhost:4567/users/USER_ID
75
+ ```
76
+
77
+ ### Analytics
78
+ ```bash
79
+ curl http://localhost:4567/analytics/department-stats
80
+ ```
81
+
82
+ ## Testing the Integration
83
+
84
+ Run the comprehensive test suite:
85
+
86
+ ```bash
87
+ ruby examples/observability/complete_test.rb
88
+ ```
89
+
90
+ This will:
91
+ 1. Start the server
92
+ 2. Test all endpoints
93
+ 3. Generate sample data
94
+ 4. Create traces in Honeycomb
95
+ 5. Clean up the server
96
+
97
+ ## Observability Features
98
+
99
+ ### Automatic Instrumentation
100
+ - **HTTP Requests**: All incoming requests are automatically traced
101
+ - **Database Queries**: Simulated database operations with realistic timings
102
+ - **External API Calls**: Net::HTTP requests are automatically instrumented
103
+ - **Error Tracking**: Exceptions and errors are captured in spans
104
+
105
+ ### Custom Business Context
106
+ Each request includes business-relevant attributes:
107
+ - User information (ID, department, etc.)
108
+ - Request metadata (pagination, filters)
109
+ - Performance metrics (database response times)
110
+ - Error context and stack traces
111
+
112
+ ### Span Hierarchy
113
+ ```
114
+ HTTP Request Span (e.g., "POST /users")
115
+ β”œβ”€β”€ Database Operation Span (e.g., "users.create")
116
+ β”œβ”€β”€ Validation Span (e.g., "validate_user_data")
117
+ └── Business Logic Span (e.g., "process_user_creation")
118
+ ```
119
+
120
+ ### Custom Metrics
121
+ - Request duration and status codes
122
+ - Database operation timing
123
+ - User activity by department
124
+ - Error rates and types
125
+
126
+ ## Viewing Traces in Honeycomb
127
+
128
+ 1. Log into your Honeycomb.io dashboard
129
+ 2. Navigate to the `rapitapir-demo` dataset
130
+ 3. You'll see traces for:
131
+ - HTTP requests with full request/response context
132
+ - Database operations with query timing
133
+ - Business operations with custom attributes
134
+ - Error traces with stack traces and context
135
+
136
+ ### Useful Queries
137
+
138
+ **Find slow requests:**
139
+ ```
140
+ duration_ms > 1000
141
+ ```
142
+
143
+ **Group by endpoint:**
144
+ ```
145
+ GROUP BY http.route
146
+ ```
147
+
148
+ **Filter by department:**
149
+ ```
150
+ user.department = "engineering"
151
+ ```
152
+
153
+ **Find errors:**
154
+ ```
155
+ status_code >= 400 OR error = true
156
+ ```
157
+
158
+ ## Architecture
159
+
160
+ ### OpenTelemetry Integration
161
+ - **SDK**: Full OpenTelemetry SDK with OTLP exporter
162
+ - **Auto-instrumentation**: Rack, Sinatra, and Net::HTTP
163
+ - **Custom spans**: Business logic and database operations
164
+ - **Baggage**: Cross-service context propagation
165
+
166
+ ### RapiTapir Extension
167
+ The `RapiTapirObservability` module provides:
168
+ - Automatic span creation for route handlers
169
+ - Business context extraction from requests
170
+ - Error handling and exception tracking
171
+ - Performance monitoring helpers
172
+
173
+ ### Trace Context
174
+ Each trace includes:
175
+ - **Service metadata**: Name, version, environment
176
+ - **Request context**: Method, path, query parameters, headers
177
+ - **User context**: ID, department, business attributes
178
+ - **Performance data**: Timing, resource usage, dependencies
179
+ - **Error information**: Exception details, stack traces
180
+
181
+ ## Best Practices
182
+
183
+ 1. **Meaningful Span Names**: Use business-relevant names like "create_user" instead of generic ones
184
+ 2. **Rich Attributes**: Include business context that helps with debugging
185
+ 3. **Error Handling**: Always capture errors with full context
186
+ 4. **Performance Monitoring**: Track both technical and business metrics
187
+ 5. **Security**: Never log sensitive data like passwords or tokens
188
+
189
+ ## Production Considerations
190
+
191
+ - **Sampling**: Configure sampling rates for high-traffic applications
192
+ - **Resource Limits**: Set memory and CPU limits for the OpenTelemetry SDK
193
+ - **Security**: Use environment variables for API keys, never commit them
194
+ - **Monitoring**: Monitor the observability system itself for health
195
+ - **Privacy**: Ensure compliance with data protection regulations
196
+
197
+ ## Troubleshooting
198
+
199
+ ### Server Won't Start
200
+ ```bash
201
+ # Check if gems are installed
202
+ bundle install
203
+
204
+ # Run from project root with bundle exec
205
+ bundle exec ruby examples/observability/honeycomb_working_example.rb
206
+ ```
207
+
208
+ ### No Traces in Honeycomb
209
+ 1. Verify API key is correct
210
+ 2. Check environment variables are loaded
211
+ 3. Confirm network connectivity to api.honeycomb.io
212
+ 4. Look for OpenTelemetry initialization messages in logs
213
+
214
+ ### Port Already in Use
215
+ ```bash
216
+ # Kill any existing processes on port 4567
217
+ lsof -ti:4567 | xargs kill -9
218
+ ```
219
+
220
+ ## Contributing
221
+
222
+ Feel free to extend this example with:
223
+ - Additional instrumentation for your specific use cases
224
+ - Custom metrics and dashboards
225
+ - Integration with other observability tools
226
+ - Performance optimizations
227
+
228
+ ---
229
+
230
+ This example demonstrates production-ready observability integration that you can adapt for your own RapiTapir applications. The patterns shown here scale from development to production environments.
@@ -0,0 +1,332 @@
1
+ # 🍯 RapiTapir Honeycomb.io Observability Example
2
+
3
+ This example demonstrates how to integrate **RapiTapir** with **Honeycomb.io** using **OpenTelemetry** for comprehensive observability, including distributed tracing, custom spans, baggage propagation, and business metrics.
4
+
5
+ ## πŸš€ Features Demonstrated
6
+
7
+ - **OpenTelemetry Integration**: Full SDK setup with Honeycomb.io OTLP exporter
8
+ - **Automatic Instrumentation**: Sinatra, Rack, HTTP, and JSON instrumentation
9
+ - **Custom Spans**: Business logic tracing with detailed attributes
10
+ - **Baggage Propagation**: Context sharing across spans
11
+ - **Error Handling**: Comprehensive error tracing and status reporting
12
+ - **Health Checks**: Traced health check endpoints
13
+ - **Business Analytics**: Custom spans for complex operations
14
+ - **Performance Monitoring**: Request timing and resource usage
15
+
16
+ ## πŸ“‹ Prerequisites
17
+
18
+ 1. **Ruby 3.2+** installed
19
+ 2. **Honeycomb.io account** (free account available at [honeycomb.io](https://ui.honeycomb.io/signup))
20
+ 3. **Honeycomb API Key** with "Can create datasets" permission
21
+
22
+ ## πŸ”§ Setup Instructions
23
+
24
+ ### 1. Install Dependencies
25
+
26
+ First, install the required OpenTelemetry gems. The main Gemfile already includes them:
27
+
28
+ ```bash
29
+ bundle install
30
+ ```
31
+
32
+ ### 2. Get Your Honeycomb API Key
33
+
34
+ 1. Sign up for a free Honeycomb account at [honeycomb.io](https://ui.honeycomb.io/signup)
35
+ 2. Go to **Environment Settings** β†’ **API Keys**
36
+ 3. Create a new API key with **"Can create datasets"** checked
37
+ 4. Copy your API key (you won't be able to see it again!)
38
+
39
+ ### 3. Configure Environment Variables
40
+
41
+ Copy the example environment file and update it with your API key:
42
+
43
+ ```bash
44
+ cd examples/observability
45
+ cp .env.example .env
46
+ ```
47
+
48
+ Edit `.env` and replace `your-honeycomb-api-key-here` with your actual API key:
49
+
50
+ ```bash
51
+ # Required: Your Honeycomb API key
52
+ OTEL_EXPORTER_OTLP_HEADERS=x-honeycomb-team=YOUR_ACTUAL_API_KEY_HERE
53
+
54
+ # Honeycomb endpoint (US instance)
55
+ OTEL_EXPORTER_OTLP_ENDPOINT=https://api.honeycomb.io
56
+
57
+ # Service configuration
58
+ OTEL_SERVICE_NAME=rapitapir-demo
59
+ OTEL_SERVICE_VERSION=1.0.0
60
+ ```
61
+
62
+ For EU instance users, use:
63
+ ```bash
64
+ OTEL_EXPORTER_OTLP_ENDPOINT=https://api.eu1.honeycomb.io
65
+ ```
66
+
67
+ ### 4. Load Environment Variables
68
+
69
+ ```bash
70
+ # Install dotenv if not already installed
71
+ gem install dotenv
72
+
73
+ # Load the environment
74
+ source .env
75
+ # Or use dotenv if you prefer
76
+ dotenv -f .env
77
+ ```
78
+
79
+ ## πŸƒβ€β™‚οΈ Running the Demo
80
+
81
+ ### Start the Server
82
+
83
+ ```bash
84
+ cd examples/observability
85
+ ruby honeycomb_example.rb
86
+ ```
87
+
88
+ The server will start on `http://localhost:4567` and display:
89
+
90
+ ```
91
+ 🍯 Starting RapiTapir Demo API with Honeycomb.io Observability
92
+ πŸ“Š Traces will be sent to: https://api.honeycomb.io
93
+ πŸ”§ Service Name: rapitapir-demo
94
+
95
+ πŸš€ Available endpoints:
96
+ GET /health - Health check
97
+ GET /users - List users
98
+ POST /users - Create user
99
+ GET /users/:id - Get user by ID
100
+ PUT /users/:id - Update user
101
+ DELETE /users/:id - Delete user
102
+ GET /analytics/department-stats - Department analytics
103
+ ```
104
+
105
+ ### Test the API
106
+
107
+ Generate some traces by making requests:
108
+
109
+ ```bash
110
+ # Health check
111
+ curl http://localhost:4567/health
112
+
113
+ # Create users
114
+ curl -X POST http://localhost:4567/users \
115
+ -H 'Content-Type: application/json' \
116
+ -d '{
117
+ "name": "Alice Engineer",
118
+ "email": "alice@example.com",
119
+ "age": 28,
120
+ "department": "engineering"
121
+ }'
122
+
123
+ curl -X POST http://localhost:4567/users \
124
+ -H 'Content-Type: application/json' \
125
+ -d '{
126
+ "name": "Bob Sales",
127
+ "email": "bob@example.com",
128
+ "age": 32,
129
+ "department": "sales"
130
+ }'
131
+
132
+ # List users with filtering and pagination
133
+ curl "http://localhost:4567/users"
134
+ curl "http://localhost:4567/users?department=engineering&page=1&limit=5"
135
+
136
+ # Get analytics (complex operation with multiple spans)
137
+ curl http://localhost:4567/analytics/department-stats
138
+
139
+ # Test error handling
140
+ curl -X POST http://localhost:4567/users \
141
+ -H 'Content-Type: application/json' \
142
+ -d '{"invalid": "data"}'
143
+ ```
144
+
145
+ ## πŸ“Š Viewing Data in Honeycomb
146
+
147
+ 1. Go to [Honeycomb.io](https://ui.honeycomb.io/) and log in
148
+ 2. You should see a new dataset called **"rapitapir-demo"** (or whatever you set as `OTEL_SERVICE_NAME`)
149
+ 3. Click on the dataset to start exploring your traces
150
+
151
+ ### Key Honeycomb Features to Explore
152
+
153
+ #### 1. **Traces View**
154
+ - See complete request flows from HTTP request to business logic
155
+ - Identify performance bottlenecks and slow operations
156
+ - Visualize parent-child span relationships
157
+
158
+ #### 2. **Useful Queries to Try**
159
+
160
+ ```sql
161
+ -- Find slow requests
162
+ WHERE duration_ms > 100
163
+
164
+ -- Find errors by type
165
+ WHERE error.type EXISTS
166
+
167
+ -- Analyze by department
168
+ GROUP BY user.department
169
+
170
+ -- Find database operations
171
+ WHERE db.operation EXISTS
172
+
173
+ -- Look at business operations
174
+ WHERE business.operation = "create_user"
175
+
176
+ -- Health check performance
177
+ WHERE business.operation = "health_check"
178
+ ```
179
+
180
+ #### 3. **Custom Attributes Added**
181
+
182
+ The example adds rich context to spans:
183
+
184
+ **HTTP Attributes:**
185
+ - `http.method`, `http.url`, `http.status_code`
186
+ - `http.user_agent`, `http.response_size`
187
+
188
+ **Business Attributes:**
189
+ - `business.operation` (create_user, list_users, etc.)
190
+ - `business.entity` (user, analytics)
191
+ - `user.id`, `user.department`
192
+
193
+ **Database Simulation:**
194
+ - `db.operation` (SELECT, INSERT, UPDATE, DELETE)
195
+ - `db.table` (users)
196
+ - Query timing and performance
197
+
198
+ **Custom Metrics:**
199
+ - `duration_ms` - Request/operation timing
200
+ - `result.count` - Number of items returned
201
+ - `pagination.*` - Pagination metadata
202
+
203
+ #### 4. **Baggage Propagation**
204
+
205
+ The example demonstrates OpenTelemetry baggage:
206
+ - `request.id` - Unique identifier for each request
207
+ - `service.name` - Service context
208
+ - `user.created` - Business event flags
209
+
210
+ ## πŸ”§ Advanced Configuration
211
+
212
+ ### Sampling for Production
213
+
214
+ For high-traffic production environments, enable sampling:
215
+
216
+ ```bash
217
+ # Keep 10% of traces (1/10)
218
+ OTEL_TRACES_SAMPLER=traceidratio
219
+ OTEL_TRACES_SAMPLER_ARG=0.1
220
+ OTEL_RESOURCE_ATTRIBUTES=SampleRate=10
221
+ ```
222
+
223
+ ### Custom Span Processors
224
+
225
+ The example includes custom span processors:
226
+
227
+ ```ruby
228
+ # Add baggage to all spans
229
+ config.add_span_processor(OpenTelemetry::Processor::Baggage::BaggageSpanProcessor.new)
230
+
231
+ # Batch export to Honeycomb
232
+ config.add_span_processor(
233
+ OpenTelemetry::SDK::Trace::Export::BatchSpanProcessor.new(
234
+ OpenTelemetry::Exporter::OTLP::Exporter.new
235
+ )
236
+ )
237
+ ```
238
+
239
+ ### Error Handling
240
+
241
+ Comprehensive error tracking:
242
+
243
+ ```ruby
244
+ rescue StandardError => e
245
+ span.set_attribute('error.type', e.class.name)
246
+ span.set_attribute('error.message', e.message)
247
+ span.status = OpenTelemetry::Trace::Status.error(e.message)
248
+ end
249
+ ```
250
+
251
+ ## πŸ—οΈ Architecture
252
+
253
+ The example demonstrates a layered observability approach:
254
+
255
+ ```
256
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
257
+ β”‚ HTTP Request (Automatic Instrumentation) β”‚
258
+ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
259
+ β”‚ Sinatra Route Handler β”‚
260
+ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
261
+ β”‚ Business Logic Spans β”‚
262
+ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
263
+ β”‚ Database/External Service Simulationβ”‚
264
+ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
265
+ β”‚ Honeycomb.io via OTLP β”‚
266
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
267
+ ```
268
+
269
+ ### Span Hierarchy Example
270
+
271
+ ```
272
+ POST /users
273
+ β”œβ”€ users.create (business logic)
274
+ β”‚ β”œβ”€ validation.user_input
275
+ β”‚ └─ database.insert.user
276
+ └─ HTTP span (automatic)
277
+ ```
278
+
279
+ ## πŸ› Troubleshooting
280
+
281
+ ### No Data in Honeycomb?
282
+
283
+ 1. **Check API Key**: Ensure your API key is correct and has "Can create datasets" permission
284
+ 2. **Check Endpoint**: US vs EU instance
285
+ 3. **Check Environment**: Make sure environment variables are loaded
286
+ 4. **Enable Debug Mode**:
287
+ ```bash
288
+ OTEL_RUBY_TRACES_EXPORTER_DEBUG=true
289
+ OTEL_LOG_LEVEL=debug
290
+ ```
291
+
292
+ ### Debugging OpenTelemetry
293
+
294
+ Add debug logging to see what's happening:
295
+
296
+ ```ruby
297
+ # Add this to the top of honeycomb_example.rb
298
+ ENV['OTEL_LOG_LEVEL'] = 'debug'
299
+ ```
300
+
301
+ ### Common Issues
302
+
303
+ 1. **Missing Dataset**: Ensure API key has "Can create datasets" permission
304
+ 2. **EU vs US Instance**: Check you're using the correct endpoint
305
+ 3. **Firewall**: Ensure outbound HTTPS to Honeycomb is allowed
306
+ 4. **Gem Conflicts**: Run `bundle install` to ensure all OpenTelemetry gems are compatible
307
+
308
+ ## πŸ“š Further Reading
309
+
310
+ - [Honeycomb OpenTelemetry Ruby Guide](https://docs.honeycomb.io/send-data/ruby/opentelemetry-sdk/)
311
+ - [OpenTelemetry Ruby Documentation](https://opentelemetry.io/docs/instrumentation/ruby/)
312
+ - [Honeycomb Query Language](https://docs.honeycomb.io/query-data/)
313
+ - [OpenTelemetry Semantic Conventions](https://opentelemetry.io/docs/specs/semconv/)
314
+
315
+ ## 🎯 Production Considerations
316
+
317
+ 1. **Sampling**: Enable sampling for high-traffic applications
318
+ 2. **Resource Attributes**: Add deployment environment, version tags
319
+ 3. **Security**: Store API keys securely (not in code)
320
+ 4. **Monitoring**: Set up alerts in Honeycomb for error rates and latency
321
+ 5. **Performance**: Monitor the overhead of instrumentation
322
+
323
+ ## 🀝 Integration with RapiTapir
324
+
325
+ This example shows how to extend RapiTapir with comprehensive observability:
326
+
327
+ - **Custom Sinatra Extension**: `RapiTapir::Extensions::HoneycombObservability`
328
+ - **Automatic Context Propagation**: Request IDs and business context
329
+ - **Health Check Integration**: Traced health checks with timing
330
+ - **Error Handling**: Structured error reporting with context
331
+
332
+ The pattern can be extended to other frameworks (Rails, Roda, etc.) and provides a foundation for production-ready observability in RapiTapir applications.