instana 2.9.0 → 2.10.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 +4 -4
- data/README.md +173 -0
- data/lib/instana/backend/host_agent_reporting_observer.rb +26 -14
- data/lib/instana/config.rb +17 -2
- data/lib/instana/exporter/otlp/aws_converter.rb +14 -3
- data/lib/instana/exporter/otlp/background_job_converter.rb +12 -1
- data/lib/instana/exporter/otlp/base_converter.rb +14 -2
- data/lib/instana/exporter/otlp/database_converter.rb +24 -4
- data/lib/instana/exporter/otlp/http_converter.rb +3 -2
- data/lib/instana/exporter/otlp/messaging_converter.rb +67 -21
- data/lib/instana/exporter/otlp/rpc_converter.rb +64 -4
- data/lib/instana/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 85a74f9236a4a35af2f74850bb0c5230a921f37b23bdf80af6b578375fe620d3
|
|
4
|
+
data.tar.gz: eaaa01ae5c3a67c7d374fff6ccdf58be1bff45e8ba36186e2617b3084abb2e90
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1338789ea5e37aa238bc08815cdbabf801ead7b17f28a9fc49e1efefecfa103ed2d0eb2958be6a50efa821169c2b4551e2b521b6f518585fa75e30a84cc92b0e
|
|
7
|
+
data.tar.gz: f1290dc8888e9e570bc2ee6a1dab5f11ac2f241726a0bf809aaa4c8fa5066d2bc142a268be3e85183052e9f26eff5a9a3377cf48b06a91acf9861f1c490f4da5
|
data/README.md
CHANGED
|
@@ -51,6 +51,179 @@ Although the gem has no configuration required for out of the box metrics and tr
|
|
|
51
51
|
|
|
52
52
|
This Ruby gem provides a simple API for tracing and also supports [OpenTracing](http://opentracing.io/). See the [Ruby Tracing SDK](https://www.ibm.com/docs/en/instana-observability/current?topic=ruby-tracing-sdk) and [OpenTracing](https://www.ibm.com/docs/en/instana-observability/current?topic=ruby-opentracing) pages for details.
|
|
53
53
|
|
|
54
|
+
## OTLP Export
|
|
55
|
+
|
|
56
|
+
The `instana` gem supports exporting traces via the **OpenTelemetry Protocol (OTLP)**
|
|
57
|
+
directly to the Instana agent's OTLP receiver, bypassing the native agent trace format.
|
|
58
|
+
OTLP export is **opt-in** — the gem behaves identically to previous versions when
|
|
59
|
+
`INSTANA_TRACING_OTLP_ENABLED` is not set.
|
|
60
|
+
|
|
61
|
+
### Overview
|
|
62
|
+
|
|
63
|
+
When OTLP export is enabled:
|
|
64
|
+
- Spans are converted from Instana's internal format to OTLP protobuf
|
|
65
|
+
- The converted spans are sent via HTTP/protobuf to the agent's OTLP port (`4318`)
|
|
66
|
+
- The endpoint is auto-derived from the same host where the Instana agent was discovered
|
|
67
|
+
- The native agent reporting path (`/com.instana.plugin.ruby/traces`) is replaced by OTLP
|
|
68
|
+
|
|
69
|
+
### Quick Start
|
|
70
|
+
|
|
71
|
+
The only required change is setting one environment variable before starting your application:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
INSTANA_TRACING_OTLP_ENABLED=true bundle exec rails server
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Expected log output (with `INSTANA_LOG_LEVEL=debug`):
|
|
78
|
+
```
|
|
79
|
+
[Instana] Using OTLP Exporter to export result code: 0
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Result code `0` = `SUCCESS`. No other configuration is needed — the endpoint is
|
|
83
|
+
automatically set to `http://<agent-host>:4318/v1/traces`.
|
|
84
|
+
|
|
85
|
+
### Gem Dependencies
|
|
86
|
+
|
|
87
|
+
`opentelemetry-exporter-otlp` is a **runtime dependency** of the `instana` gem and
|
|
88
|
+
is installed automatically. No additional gems are required.
|
|
89
|
+
|
|
90
|
+
> **Note:** gRPC (`OTEL_EXPORTER_OTLP_PROTOCOL=grpc`) is not supported.
|
|
91
|
+
> Only `http/protobuf` is supported and tested.
|
|
92
|
+
|
|
93
|
+
### Environment Variables
|
|
94
|
+
|
|
95
|
+
| Variable | Type | Default | Description |
|
|
96
|
+
|---|---|---|---|
|
|
97
|
+
| `INSTANA_TRACING_OTLP_ENABLED` | Boolean | `false` | Enables OTLP export. Valid values: `true`, `1`, `yes` |
|
|
98
|
+
| `OTEL_EXPORTER_OTLP_ENDPOINT` | String (URL) | auto-derived from agent host | **Base** endpoint URL. `/v1/traces` is appended automatically. |
|
|
99
|
+
| `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` | String (URL) | `<OTEL_EXPORTER_OTLP_ENDPOINT>/v1/traces` | **Fully-qualified** trace endpoint. Used as-is; overrides `OTEL_EXPORTER_OTLP_ENDPOINT`. |
|
|
100
|
+
| `OTEL_EXPORTER_OTLP_PROTOCOL` | String | `http/protobuf` | Transport protocol. Only `http/protobuf` is supported. |
|
|
101
|
+
| `OTEL_EXPORTER_OTLP_HEADERS` | String | — | Comma-separated `key=value` auth headers. e.g. `api-key=secret,x-tenant-id=myorg` |
|
|
102
|
+
| `OTEL_EXPORTER_OTLP_TIMEOUT` | Integer (ms) | `10000` | Maximum time to wait for export completion. |
|
|
103
|
+
| `OTEL_EXPORTER_OTLP_COMPRESSION` | String | — | Compression algorithm. Valid value: `gzip`. |
|
|
104
|
+
| `OTEL_EXPORTER_OTLP_CERTIFICATE` | String (path) | — | Path to CA certificate file for TLS verification. |
|
|
105
|
+
| `OTEL_EXPORTER_OTLP_CLIENT_KEY` | String (path) | — | Path to client private key file for mutual TLS. |
|
|
106
|
+
| `OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE` | String (path) | — | Path to client certificate file for mutual TLS. |
|
|
107
|
+
| `OTEL_EXPORTER_OTLP_INSECURE` | Boolean | `false` | Disable TLS certificate verification. |
|
|
108
|
+
| `OTEL_SEMCONV_STABILITY_OPT_IN` | String | `stable` | Semantic convention stability level. Valid values: `stable`, `development`. |
|
|
109
|
+
|
|
110
|
+
> **Endpoint precedence:** `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` > `OTEL_EXPORTER_OTLP_ENDPOINT` > auto-derived from agent host
|
|
111
|
+
|
|
112
|
+
### YAML Configuration
|
|
113
|
+
|
|
114
|
+
When `INSTANA_CONFIG_PATH` points to a YAML file, OTLP settings are placed under
|
|
115
|
+
the `tracing.otlp` key. YAML configuration takes precedence over environment variables.
|
|
116
|
+
|
|
117
|
+
**Minimal example** (`config/instana.yml`):
|
|
118
|
+
```yaml
|
|
119
|
+
tracing:
|
|
120
|
+
otlp:
|
|
121
|
+
enabled: true
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
**Full example:**
|
|
125
|
+
```yaml
|
|
126
|
+
tracing:
|
|
127
|
+
otlp:
|
|
128
|
+
enabled: true
|
|
129
|
+
endpoint: "http://localhost:4318/v1/traces"
|
|
130
|
+
protocol: "http/protobuf"
|
|
131
|
+
timeout: 10000
|
|
132
|
+
compression: "gzip"
|
|
133
|
+
headers:
|
|
134
|
+
x-instana-key: "YOUR_API_KEY"
|
|
135
|
+
x-tenant-id: "YOUR_TENANT"
|
|
136
|
+
certificate: "/path/to/ca-cert.pem"
|
|
137
|
+
client_key: "/path/to/client-key.pem"
|
|
138
|
+
client_certificate: "/path/to/client-cert.pem"
|
|
139
|
+
insecure: false
|
|
140
|
+
semconv_stability: "stable"
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Start the application:
|
|
144
|
+
```bash
|
|
145
|
+
INSTANA_CONFIG_PATH=config/instana.yml bundle exec rails server
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Configuration Precedence
|
|
149
|
+
|
|
150
|
+
Settings are resolved in this order (highest wins):
|
|
151
|
+
|
|
152
|
+
```
|
|
153
|
+
INSTANA_CONFIG_PATH YAML → Environment variables → Agent config → Defaults
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
This means a YAML file always wins over env vars. Agent-provided config (pushed
|
|
157
|
+
via the Instana agent's discovery payload) is applied after env vars but can be
|
|
158
|
+
overridden by YAML or env vars set at startup.
|
|
159
|
+
|
|
160
|
+
### TLS / mTLS
|
|
161
|
+
|
|
162
|
+
**Server-side TLS** (verify the collector's certificate):
|
|
163
|
+
```bash
|
|
164
|
+
INSTANA_TRACING_OTLP_ENABLED=true \
|
|
165
|
+
OTEL_EXPORTER_OTLP_ENDPOINT=https://your-collector:4318/v1/traces \
|
|
166
|
+
OTEL_EXPORTER_OTLP_CERTIFICATE=/path/to/ca-cert.pem \
|
|
167
|
+
bundle exec rails server
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
**Mutual TLS** (client certificate authentication):
|
|
171
|
+
```bash
|
|
172
|
+
INSTANA_TRACING_OTLP_ENABLED=true \
|
|
173
|
+
OTEL_EXPORTER_OTLP_ENDPOINT=https://your-collector:4318/v1/traces \
|
|
174
|
+
OTEL_EXPORTER_OTLP_CERTIFICATE=/path/to/ca-cert.pem \
|
|
175
|
+
OTEL_EXPORTER_OTLP_CLIENT_KEY=/path/to/client-key.pem \
|
|
176
|
+
OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE=/path/to/client-cert.pem \
|
|
177
|
+
bundle exec rails server
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### Troubleshooting
|
|
181
|
+
|
|
182
|
+
**OTLP export is not happening — spans go via the native path**
|
|
183
|
+
|
|
184
|
+
OTLP is disabled by default. Check that `INSTANA_TRACING_OTLP_ENABLED=true` is set
|
|
185
|
+
in the process environment before the gem initialises (i.e. before `require 'instana'`
|
|
186
|
+
or Rails boot). Verify with:
|
|
187
|
+
```bash
|
|
188
|
+
INSTANA_LOG_LEVEL=debug bundle exec rails server
|
|
189
|
+
# Look for: "Using OTLP Exporter" vs "Using Instana Native Exporter"
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
**`Failed to initialize OTLP exporter` in the log**
|
|
193
|
+
|
|
194
|
+
The exporter could not be constructed. Common causes:
|
|
195
|
+
- `OTEL_EXPORTER_OTLP_CERTIFICATE` path does not exist or is not readable
|
|
196
|
+
- `OTEL_EXPORTER_OTLP_CLIENT_KEY` / `OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE` path invalid
|
|
197
|
+
- An unsupported protocol (e.g. `grpc`) was set — only `http/protobuf` is supported
|
|
198
|
+
|
|
199
|
+
The gem falls back to `@otlp_exporter = nil` and logs an `ERROR` line with the
|
|
200
|
+
exception message. Check that message for the root cause.
|
|
201
|
+
|
|
202
|
+
**`result code: 1` (FAILURE) — spans not arriving**
|
|
203
|
+
|
|
204
|
+
The exporter initialised but the export request failed. Common causes:
|
|
205
|
+
- The Instana agent is not running or OTLP is not enabled on the agent side
|
|
206
|
+
- `OTEL_EXPORTER_OTLP_ENDPOINT` points to a wrong host or port
|
|
207
|
+
- `OTEL_EXPORTER_OTLP_ENDPOINT` was set to a base URL like `http://host:4318`
|
|
208
|
+
without `/v1/traces` — this was a known bug fixed in v2.9.0 (the sensor now
|
|
209
|
+
appends the path automatically)
|
|
210
|
+
- A firewall is blocking port `4318`
|
|
211
|
+
|
|
212
|
+
Verify the agent OTLP port is reachable:
|
|
213
|
+
```bash
|
|
214
|
+
curl -s -o /dev/null -w "%{http_code}" \
|
|
215
|
+
-X POST http://localhost:4318/v1/traces \
|
|
216
|
+
-H "Content-Type: application/x-protobuf"
|
|
217
|
+
# 200 or 415 = port open; "connection refused" = agent OTLP not enabled
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
**`HTTP request path is empty` exception (pre-v2.9.0)**
|
|
221
|
+
|
|
222
|
+
If you are on a version earlier than 2.9.0 and pass a base URL to
|
|
223
|
+
`OTEL_EXPORTER_OTLP_ENDPOINT` (without `/v1/traces`), the `opentelemetry-exporter-otlp`
|
|
224
|
+
gem crashes with `HTTP request path is empty`. Upgrade to v2.9.0 or later, or use
|
|
225
|
+
`OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` with the full path instead.
|
|
226
|
+
|
|
54
227
|
## Documentation
|
|
55
228
|
|
|
56
229
|
You can find more documentation covering supported components and minimum versions in the Instana [documentation portal](https://www.ibm.com/docs/en/instana-observability/current?topic=technologies-monitoring-ruby).
|
|
@@ -186,11 +186,12 @@ module Instana
|
|
|
186
186
|
|
|
187
187
|
endpoint = resolve_otlp_endpoint(config[:endpoint], config[:config_source])
|
|
188
188
|
opts = { endpoint: endpoint, timeout: config[:timeout] / 1000.0 }
|
|
189
|
-
opts[:compression]
|
|
190
|
-
opts[:headers]
|
|
191
|
-
opts[:certificate_file]
|
|
192
|
-
opts[:client_certificate_file] = config[:client_certificate]
|
|
193
|
-
opts[:client_key_file]
|
|
189
|
+
opts[:compression] = config[:compression] if config[:compression]
|
|
190
|
+
opts[:headers] = config[:headers] if config[:headers]&.any?
|
|
191
|
+
opts[:certificate_file] = config[:certificate] if config[:certificate]
|
|
192
|
+
opts[:client_certificate_file] = config[:client_certificate] if config[:client_certificate]
|
|
193
|
+
opts[:client_key_file] = config[:client_key] if config[:client_key]
|
|
194
|
+
opts[:ssl_verify_mode] = OpenSSL::SSL::VERIFY_NONE if config[:insecure]
|
|
194
195
|
|
|
195
196
|
@otlp_exporter = OpenTelemetry::Exporter::OTLP::Exporter.new(**opts)
|
|
196
197
|
rescue StandardError => e
|
|
@@ -198,21 +199,32 @@ module Instana
|
|
|
198
199
|
@otlp_exporter = nil
|
|
199
200
|
end
|
|
200
201
|
|
|
201
|
-
# Derive the OTLP endpoint from the discovered agent host when no explicit
|
|
202
|
-
# endpoint has been configured (config_source == 'default').
|
|
203
202
|
OTLP_DEFAULT_PORT = 4318
|
|
204
203
|
OTLP_TRACES_PATH = '/v1/traces'.freeze
|
|
205
204
|
|
|
205
|
+
# Returns a fully-qualified OTLP traces endpoint.
|
|
206
|
+
#
|
|
207
|
+
# When config_source is 'default', builds the endpoint from the discovered
|
|
208
|
+
# agent host so OTLP traffic goes to the same host as metrics/traces.
|
|
209
|
+
#
|
|
210
|
+
# For user-supplied endpoints, appends '/v1/traces' when the URL has no
|
|
211
|
+
# path, because OTEL_EXPORTER_OTLP_ENDPOINT is a base URL and the
|
|
212
|
+
# opentelemetry-exporter-otlp gem only auto-appends the path when no
|
|
213
|
+
# endpoint is given at all.
|
|
206
214
|
def resolve_otlp_endpoint(endpoint, config_source)
|
|
207
|
-
|
|
215
|
+
if config_source == 'default'
|
|
216
|
+
agent_host = @client&.host
|
|
217
|
+
return endpoint unless agent_host
|
|
208
218
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
# OTLP HTTP port and traces path.
|
|
212
|
-
agent_host = @client&.host
|
|
213
|
-
return endpoint unless agent_host
|
|
219
|
+
return "http://#{agent_host}:#{OTLP_DEFAULT_PORT}#{OTLP_TRACES_PATH}"
|
|
220
|
+
end
|
|
214
221
|
|
|
215
|
-
|
|
222
|
+
# User-supplied: append the traces path if no path was given.
|
|
223
|
+
uri = URI.parse(endpoint)
|
|
224
|
+
uri.path = OTLP_TRACES_PATH if uri.path.empty? || uri.path == '/'
|
|
225
|
+
uri.to_s
|
|
226
|
+
rescue URI::InvalidURIError
|
|
227
|
+
endpoint
|
|
216
228
|
end
|
|
217
229
|
end
|
|
218
230
|
end
|
data/lib/instana/config.rb
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
require 'yaml'
|
|
5
5
|
|
|
6
6
|
module Instana
|
|
7
|
-
class Config
|
|
7
|
+
class Config # rubocop:disable Metrics/ClassLength
|
|
8
8
|
|
|
9
9
|
LEGACY_TRACING_KEY = 'com.instana.tracing'.freeze
|
|
10
10
|
TRACING_KEY = 'tracing'.freeze
|
|
@@ -63,6 +63,9 @@ module Instana
|
|
|
63
63
|
certificate: nil,
|
|
64
64
|
client_key: nil,
|
|
65
65
|
client_certificate: nil,
|
|
66
|
+
protocol: 'http/protobuf',
|
|
67
|
+
semconv_stability: 'stable',
|
|
68
|
+
insecure: false,
|
|
66
69
|
config_source: 'default'
|
|
67
70
|
}
|
|
68
71
|
read_otlp_config
|
|
@@ -257,6 +260,9 @@ module Instana
|
|
|
257
260
|
@config[:otlp][:certificate] = otlp_config['certificate'] if otlp_config['certificate']
|
|
258
261
|
@config[:otlp][:client_key] = otlp_config['client_key'] if otlp_config['client_key']
|
|
259
262
|
@config[:otlp][:client_certificate] = otlp_config['client_certificate'] if otlp_config['client_certificate']
|
|
263
|
+
@config[:otlp][:protocol] = otlp_config['protocol'] if otlp_config['protocol']
|
|
264
|
+
@config[:otlp][:semconv_stability] = otlp_config['semconv_stability'] if otlp_config['semconv_stability']
|
|
265
|
+
@config[:otlp][:insecure] = truthy?(otlp_config['insecure']) unless otlp_config['insecure'].nil?
|
|
260
266
|
@config[:otlp][:config_source] = 'agent'
|
|
261
267
|
end
|
|
262
268
|
|
|
@@ -381,6 +387,9 @@ module Instana
|
|
|
381
387
|
result[:certificate] = otlp_yaml['certificate'] if otlp_yaml['certificate']
|
|
382
388
|
result[:client_key] = otlp_yaml['client_key'] if otlp_yaml['client_key']
|
|
383
389
|
result[:client_certificate] = otlp_yaml['client_certificate'] if otlp_yaml['client_certificate']
|
|
390
|
+
result[:protocol] = otlp_yaml['protocol'] if otlp_yaml['protocol']
|
|
391
|
+
result[:semconv_stability] = otlp_yaml['semconv_stability'] if otlp_yaml['semconv_stability']
|
|
392
|
+
result[:insecure] = truthy?(otlp_yaml['insecure']) unless otlp_yaml['insecure'].nil?
|
|
384
393
|
result.empty? ? nil : result
|
|
385
394
|
end
|
|
386
395
|
|
|
@@ -399,6 +408,9 @@ module Instana
|
|
|
399
408
|
result[:certificate] = raw[:certificate] if raw[:certificate]
|
|
400
409
|
result[:client_key] = raw[:client_key] if raw[:client_key]
|
|
401
410
|
result[:client_certificate] = raw[:client_cert] if raw[:client_cert]
|
|
411
|
+
result[:protocol] = raw[:protocol] if raw[:protocol]
|
|
412
|
+
result[:semconv_stability] = raw[:semconv_stability] if raw[:semconv_stability]
|
|
413
|
+
result[:insecure] = truthy?(raw[:insecure_raw]) unless raw[:insecure_raw].nil?
|
|
402
414
|
result
|
|
403
415
|
end
|
|
404
416
|
|
|
@@ -413,7 +425,10 @@ module Instana
|
|
|
413
425
|
headers_raw: ENV.fetch('OTEL_EXPORTER_OTLP_TRACES_HEADERS', nil) || ENV.fetch('OTEL_EXPORTER_OTLP_HEADERS', nil),
|
|
414
426
|
certificate: ENV.fetch('OTEL_EXPORTER_OTLP_CERTIFICATE', nil),
|
|
415
427
|
client_key: ENV.fetch('OTEL_EXPORTER_OTLP_CLIENT_KEY', nil),
|
|
416
|
-
client_cert: ENV.fetch('OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE', nil)
|
|
428
|
+
client_cert: ENV.fetch('OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE', nil),
|
|
429
|
+
protocol: ENV.fetch('OTEL_EXPORTER_OTLP_PROTOCOL', nil),
|
|
430
|
+
semconv_stability: ENV.fetch('OTEL_SEMCONV_STABILITY_OPT_IN', nil),
|
|
431
|
+
insecure_raw: ENV.fetch('OTEL_EXPORTER_OTLP_INSECURE', nil)
|
|
417
432
|
}
|
|
418
433
|
end
|
|
419
434
|
|
|
@@ -6,6 +6,9 @@ require_relative 'base_converter'
|
|
|
6
6
|
require 'opentelemetry/semconv/incubating/messaging'
|
|
7
7
|
require 'opentelemetry/semconv/db'
|
|
8
8
|
require 'opentelemetry/semconv/incubating/db'
|
|
9
|
+
require 'opentelemetry/semconv/incubating/rpc'
|
|
10
|
+
require 'opentelemetry/semconv/incubating/cloud'
|
|
11
|
+
require 'opentelemetry/semconv/incubating/faas'
|
|
9
12
|
|
|
10
13
|
module Instana
|
|
11
14
|
module Exporter
|
|
@@ -128,10 +131,18 @@ module Instana
|
|
|
128
131
|
def convert_s3_attributes(attributes, s3_data)
|
|
129
132
|
return unless s3_data
|
|
130
133
|
|
|
131
|
-
add_attribute(attributes,
|
|
134
|
+
add_attribute(attributes, Instana::Exporter::Otlp::RPC_SYSTEM_ATTR, 'aws-api')
|
|
135
|
+
add_attribute(attributes, OpenTelemetry::SemConv::Incubating::RPC::RPC_METHOD, s3_rpc_method(s3_data[:op]))
|
|
136
|
+
add_attribute(attributes, OpenTelemetry::SemConv::Incubating::CLOUD::CLOUD_PROVIDER, 'aws')
|
|
137
|
+
add_attribute(attributes, OpenTelemetry::SemConv::Incubating::CLOUD::CLOUD_REGION, s3_data[:region])
|
|
132
138
|
add_attribute(attributes, 'aws.s3.bucket', s3_data[:bucket])
|
|
133
139
|
add_attribute(attributes, 'aws.s3.key', s3_data[:key])
|
|
134
|
-
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def s3_rpc_method(operation)
|
|
143
|
+
return unless operation
|
|
144
|
+
|
|
145
|
+
"S3.#{operation}"
|
|
135
146
|
end
|
|
136
147
|
|
|
137
148
|
def convert_lambda_attributes(attributes, lambda_data)
|
|
@@ -140,7 +151,7 @@ module Instana
|
|
|
140
151
|
add_attribute(attributes, 'aws.service', 'lambda')
|
|
141
152
|
add_attribute(attributes, 'aws.lambda.function_name', lambda_data[:function])
|
|
142
153
|
add_attribute(attributes, 'aws.lambda.invocation_type', lambda_data[:type])
|
|
143
|
-
add_attribute(attributes,
|
|
154
|
+
add_attribute(attributes, OpenTelemetry::SemConv::Incubating::FAAS::FAAS_INVOKED_NAME, lambda_data[:function])
|
|
144
155
|
end
|
|
145
156
|
end
|
|
146
157
|
end
|
|
@@ -41,6 +41,8 @@ module Instana
|
|
|
41
41
|
convert_job_attributes(attributes, span[:'resque-client'] || span[:data]&.[](:'resque-client'), 'resque', 'publish')
|
|
42
42
|
elsif span_type == 'resque-worker'
|
|
43
43
|
convert_job_attributes(attributes, span[:'resque-worker'] || span[:data]&.[](:'resque-worker'), 'resque', 'process')
|
|
44
|
+
elsif span_type == 'activejob'
|
|
45
|
+
convert_activejob_attributes(attributes, span[:data]&.[](:activejob))
|
|
44
46
|
end
|
|
45
47
|
|
|
46
48
|
attributes
|
|
@@ -53,13 +55,22 @@ module Instana
|
|
|
53
55
|
|
|
54
56
|
add_attribute(attributes, OpenTelemetry::SemConv::Incubating::MESSAGING::MESSAGING_SYSTEM, system)
|
|
55
57
|
add_attribute(attributes, OpenTelemetry::SemConv::Incubating::MESSAGING::MESSAGING_DESTINATION_NAME, data[:queue] || data['queue'])
|
|
56
|
-
add_attribute(attributes, OpenTelemetry::SemConv::Incubating::MESSAGING::
|
|
58
|
+
add_attribute(attributes, OpenTelemetry::SemConv::Incubating::MESSAGING::MESSAGING_OPERATION_NAME, operation)
|
|
57
59
|
add_attribute(attributes, OpenTelemetry::SemConv::Incubating::MESSAGING::MESSAGING_MESSAGE_ID, data[:job_id] || data['job_id'])
|
|
58
60
|
add_attribute(attributes, OpenTelemetry::SemConv::Incubating::MESSAGING::MESSAGING_CONSUMER_GROUP_NAME, data[:job] || data['job'])
|
|
59
61
|
add_attribute(attributes, OpenTelemetry::SemConv::SERVER::SERVER_ADDRESS, extract_host(data[:'redis-url'] || data['redis-url']))
|
|
60
62
|
add_attribute(attributes, OpenTelemetry::SemConv::SERVER::SERVER_PORT, extract_port(data[:'redis-url'] || data['redis-url']))
|
|
61
63
|
end
|
|
62
64
|
|
|
65
|
+
def convert_activejob_attributes(attributes, data)
|
|
66
|
+
return unless data
|
|
67
|
+
|
|
68
|
+
add_attribute(attributes, OpenTelemetry::SemConv::Incubating::MESSAGING::MESSAGING_SYSTEM, 'activejob')
|
|
69
|
+
add_attribute(attributes, OpenTelemetry::SemConv::Incubating::MESSAGING::MESSAGING_DESTINATION_NAME, data[:queue] || data['queue'])
|
|
70
|
+
add_attribute(attributes, OpenTelemetry::SemConv::Incubating::MESSAGING::MESSAGING_OPERATION_NAME, data[:action] || data['action'])
|
|
71
|
+
add_attribute(attributes, OpenTelemetry::SemConv::Incubating::MESSAGING::MESSAGING_MESSAGE_ID, data[:job_id] || data['job_id'])
|
|
72
|
+
end
|
|
73
|
+
|
|
63
74
|
def extract_host(connection)
|
|
64
75
|
return nil unless connection
|
|
65
76
|
|
|
@@ -5,10 +5,22 @@
|
|
|
5
5
|
require_relative 'resource'
|
|
6
6
|
require 'opentelemetry/trace'
|
|
7
7
|
require 'forwardable'
|
|
8
|
+
require 'opentelemetry/semconv/incubating/rpc'
|
|
8
9
|
|
|
9
10
|
module Instana
|
|
10
11
|
module Exporter
|
|
11
12
|
module Otlp
|
|
13
|
+
# Compatibility shim: RPC_SYSTEM_NAME was added in a newer release of
|
|
14
|
+
# opentelemetry-semantic_conventions. Fall back to the deprecated
|
|
15
|
+
# RPC_SYSTEM constant ('rpc.system') on older installs (e.g. Ruby 3.2
|
|
16
|
+
# lockfiles that resolve an earlier gem version).
|
|
17
|
+
RPC_SYSTEM_ATTR =
|
|
18
|
+
if OpenTelemetry::SemConv::Incubating::RPC.const_defined?(:RPC_SYSTEM_NAME)
|
|
19
|
+
OpenTelemetry::SemConv::Incubating::RPC::RPC_SYSTEM_NAME
|
|
20
|
+
else
|
|
21
|
+
OpenTelemetry::SemConv::Incubating::RPC::RPC_SYSTEM
|
|
22
|
+
end
|
|
23
|
+
|
|
12
24
|
# Base class for all OTLP span converters
|
|
13
25
|
#
|
|
14
26
|
# Provides common interface and shared functionality for converting Instana spans
|
|
@@ -312,12 +324,12 @@ module Instana
|
|
|
312
324
|
timestamp = calculate_end_timestamp
|
|
313
325
|
|
|
314
326
|
if stacktrace
|
|
315
|
-
attrs = {
|
|
327
|
+
attrs = {}
|
|
316
328
|
attrs['exception.message'] = error_msg if error_msg
|
|
317
329
|
attrs['exception.stacktrace'] = stacktrace
|
|
318
330
|
[Event.new('exception', attrs, timestamp)]
|
|
319
331
|
else
|
|
320
|
-
[Event.new('error', {
|
|
332
|
+
[Event.new('error', {}, timestamp)]
|
|
321
333
|
end
|
|
322
334
|
end
|
|
323
335
|
|
|
@@ -82,32 +82,51 @@ module Instana
|
|
|
82
82
|
parts.empty? ? 'mongodb' : parts.join('.')
|
|
83
83
|
end
|
|
84
84
|
|
|
85
|
+
# Normalize an ActiveRecord/Sequel adapter name to OTel db.system.name.
|
|
86
|
+
# Only adapters that are actively instrumented and tested are listed here.
|
|
87
|
+
DB_SYSTEM_NORMALIZATION = {
|
|
88
|
+
'mysql2' => 'mysql',
|
|
89
|
+
'sqlite3' => 'sqlite',
|
|
90
|
+
'postgresql' => 'postgresql',
|
|
91
|
+
'mysql' => 'mysql',
|
|
92
|
+
'sqlite' => 'sqlite'
|
|
93
|
+
}.freeze
|
|
94
|
+
|
|
95
|
+
def normalize_db_system(adapter)
|
|
96
|
+
return unless adapter
|
|
97
|
+
|
|
98
|
+
DB_SYSTEM_NORMALIZATION.fetch(adapter.to_s.downcase, adapter.to_s.downcase)
|
|
99
|
+
end
|
|
100
|
+
|
|
85
101
|
def convert_activerecord_attributes(attributes, ar_data)
|
|
86
102
|
return unless ar_data
|
|
87
103
|
|
|
88
|
-
add_attribute(attributes, OpenTelemetry::SemConv::DB::DB_SYSTEM_NAME, ar_data[:adapter])
|
|
104
|
+
add_attribute(attributes, OpenTelemetry::SemConv::DB::DB_SYSTEM_NAME, normalize_db_system(ar_data[:adapter]))
|
|
89
105
|
add_attribute(attributes, OpenTelemetry::SemConv::DB::DB_NAMESPACE, ar_data[:db])
|
|
90
106
|
add_attribute(attributes, OpenTelemetry::SemConv::DB::DB_QUERY_TEXT, ar_data[:sql])
|
|
91
107
|
add_attribute(attributes, OpenTelemetry::SemConv::Incubating::DB::DB_USER, ar_data[:username])
|
|
92
108
|
add_attribute(attributes, OpenTelemetry::SemConv::SERVER::SERVER_ADDRESS, ar_data[:host])
|
|
109
|
+
add_attribute(attributes, OpenTelemetry::SemConv::Incubating::DB::DB_COLLECTION_NAME, ar_data[:table])
|
|
93
110
|
end
|
|
94
111
|
|
|
95
112
|
def convert_sequel_attributes(attributes, seq_data)
|
|
96
113
|
return unless seq_data
|
|
97
114
|
|
|
98
|
-
add_attribute(attributes, OpenTelemetry::SemConv::DB::DB_SYSTEM_NAME, seq_data[:adapter])
|
|
115
|
+
add_attribute(attributes, OpenTelemetry::SemConv::DB::DB_SYSTEM_NAME, normalize_db_system(seq_data[:adapter]))
|
|
99
116
|
add_attribute(attributes, OpenTelemetry::SemConv::DB::DB_NAMESPACE, seq_data[:db])
|
|
100
117
|
add_attribute(attributes, OpenTelemetry::SemConv::DB::DB_QUERY_TEXT, seq_data[:sql])
|
|
101
118
|
add_attribute(attributes, OpenTelemetry::SemConv::Incubating::DB::DB_USER, seq_data[:username])
|
|
102
119
|
add_attribute(attributes, OpenTelemetry::SemConv::SERVER::SERVER_ADDRESS, seq_data[:host])
|
|
120
|
+
add_attribute(attributes, OpenTelemetry::SemConv::Incubating::DB::DB_COLLECTION_NAME, seq_data[:table])
|
|
103
121
|
end
|
|
104
122
|
|
|
105
123
|
def convert_redis_attributes(attributes, redis_data)
|
|
106
124
|
return unless redis_data
|
|
107
125
|
|
|
108
126
|
add_attribute(attributes, OpenTelemetry::SemConv::DB::DB_SYSTEM_NAME, 'redis')
|
|
127
|
+
add_attribute(attributes, OpenTelemetry::SemConv::DB::DB_OPERATION_NAME, redis_data[:command])
|
|
109
128
|
add_attribute(attributes, OpenTelemetry::SemConv::DB::DB_QUERY_TEXT, redis_data[:command])
|
|
110
|
-
add_attribute(attributes,
|
|
129
|
+
add_attribute(attributes, OpenTelemetry::SemConv::DB::DB_NAMESPACE, redis_data[:db]&.to_s)
|
|
111
130
|
add_attribute(attributes, OpenTelemetry::SemConv::SERVER::SERVER_ADDRESS, extract_host(redis_data[:connection]))
|
|
112
131
|
add_attribute(attributes, OpenTelemetry::SemConv::SERVER::SERVER_PORT, extract_port(redis_data[:connection]))
|
|
113
132
|
end
|
|
@@ -119,7 +138,7 @@ module Instana
|
|
|
119
138
|
add_attribute(attributes, OpenTelemetry::SemConv::DB::DB_OPERATION_NAME, mc_data[:command])
|
|
120
139
|
add_attribute(attributes, 'db.memcached.key', mc_data[:key])
|
|
121
140
|
add_attribute(attributes, 'db.memcached.keys', mc_data[:keys])
|
|
122
|
-
add_attribute(attributes,
|
|
141
|
+
add_attribute(attributes, OpenTelemetry::SemConv::DB::DB_NAMESPACE, mc_data[:namespace])
|
|
123
142
|
add_attribute(attributes, OpenTelemetry::SemConv::SERVER::SERVER_ADDRESS, extract_host(mc_data[:server]))
|
|
124
143
|
add_attribute(attributes, OpenTelemetry::SemConv::SERVER::SERVER_PORT, extract_port(mc_data[:server]))
|
|
125
144
|
end
|
|
@@ -131,6 +150,7 @@ module Instana
|
|
|
131
150
|
add_attribute(attributes, OpenTelemetry::SemConv::DB::DB_NAMESPACE, mongo_data[:namespace])
|
|
132
151
|
add_attribute(attributes, OpenTelemetry::SemConv::DB::DB_OPERATION_NAME, mongo_data[:command])
|
|
133
152
|
add_attribute(attributes, OpenTelemetry::SemConv::DB::DB_QUERY_TEXT, mongo_data[:json])
|
|
153
|
+
add_attribute(attributes, OpenTelemetry::SemConv::Incubating::DB::DB_COLLECTION_NAME, mongo_data[:collection])
|
|
134
154
|
add_attribute(attributes, OpenTelemetry::SemConv::SERVER::SERVER_ADDRESS, mongo_data.dig(:peer, :hostname))
|
|
135
155
|
add_attribute(attributes, OpenTelemetry::SemConv::SERVER::SERVER_PORT, mongo_data.dig(:peer, :port))
|
|
136
156
|
end
|
|
@@ -7,6 +7,7 @@ require 'opentelemetry/semconv/http'
|
|
|
7
7
|
require 'opentelemetry/semconv/url'
|
|
8
8
|
require 'opentelemetry/semconv/server'
|
|
9
9
|
require 'opentelemetry/semconv/user_agent'
|
|
10
|
+
require 'opentelemetry/semconv/network'
|
|
10
11
|
|
|
11
12
|
module Instana
|
|
12
13
|
module Exporter
|
|
@@ -120,8 +121,8 @@ module Instana
|
|
|
120
121
|
name = parts[0].downcase
|
|
121
122
|
version = parts[1]
|
|
122
123
|
|
|
123
|
-
add_attribute(attributes,
|
|
124
|
-
add_attribute(attributes,
|
|
124
|
+
add_attribute(attributes, OpenTelemetry::SemConv::NETWORK::NETWORK_PROTOCOL_NAME, name)
|
|
125
|
+
add_attribute(attributes, OpenTelemetry::SemConv::NETWORK::NETWORK_PROTOCOL_VERSION, version)
|
|
125
126
|
end
|
|
126
127
|
end
|
|
127
128
|
end
|
|
@@ -11,15 +11,36 @@ module Instana
|
|
|
11
11
|
module Otlp
|
|
12
12
|
# Converter for messaging spans to OTLP format
|
|
13
13
|
class MessagingConverter < BaseConverter
|
|
14
|
-
# Build OTel-compliant span name for messaging
|
|
14
|
+
# Build OTel-compliant span name for messaging spans
|
|
15
15
|
#
|
|
16
|
-
# Formula per SPAN_NAME_PATTERNS.txt Section 3 (bunny/AMQP):
|
|
17
|
-
# publish → "{exchange} publish" (or "{queue} publish" when no exchange)
|
|
18
|
-
# receive → "{queue} receive"
|
|
16
|
+
# Formula per SPAN_NAME_PATTERNS.txt Section 3 (bunny/AMQP / Kafka):
|
|
17
|
+
# RabbitMQ publish → "{exchange} publish" (or "{queue} publish" when no exchange)
|
|
18
|
+
# RabbitMQ receive → "{queue} receive"
|
|
19
|
+
# Kafka → "{service} {access}" (e.g., "orders send")
|
|
19
20
|
#
|
|
20
21
|
# @return [String] The span name
|
|
21
22
|
def span_name
|
|
22
|
-
rabbitmq_data = span[:data]&.[](:rabbitmq)
|
|
23
|
+
if (rabbitmq_data = span[:data]&.[](:rabbitmq))
|
|
24
|
+
rabbitmq_span_name(rabbitmq_data)
|
|
25
|
+
elsif (kafka_data = span[:data]&.[](:kafka))
|
|
26
|
+
kafka_span_name(kafka_data)
|
|
27
|
+
else
|
|
28
|
+
super
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def convert_attributes
|
|
33
|
+
attributes = {}
|
|
34
|
+
|
|
35
|
+
convert_rabbitmq_attributes(attributes, span[:data]&.[](:rabbitmq))
|
|
36
|
+
convert_kafka_attributes(attributes, span[:data]&.[](:kafka))
|
|
37
|
+
|
|
38
|
+
attributes
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
def rabbitmq_span_name(rabbitmq_data)
|
|
23
44
|
sort = rabbitmq_data[:sort].to_s
|
|
24
45
|
|
|
25
46
|
if sort == 'publish'
|
|
@@ -32,26 +53,51 @@ module Instana
|
|
|
32
53
|
end
|
|
33
54
|
end
|
|
34
55
|
|
|
35
|
-
def
|
|
36
|
-
|
|
56
|
+
def kafka_span_name(kafka_data)
|
|
57
|
+
service = kafka_data[:service].to_s.strip
|
|
58
|
+
access = kafka_data[:access].to_s.strip
|
|
59
|
+
parts = [service, access].reject(&:empty?)
|
|
60
|
+
parts.empty? ? 'kafka' : parts.join(' ')
|
|
61
|
+
end
|
|
37
62
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
add_attribute(attributes, OpenTelemetry::SemConv::Incubating::MESSAGING::MESSAGING_SYSTEM, 'rabbitmq')
|
|
41
|
-
add_attribute(attributes, OpenTelemetry::SemConv::Incubating::MESSAGING::MESSAGING_DESTINATION_NAME,
|
|
42
|
-
rabbitmq_destination_name(rabbitmq_data))
|
|
43
|
-
add_attribute(attributes, OpenTelemetry::SemConv::Incubating::MESSAGING::MESSAGING_RABBITMQ_DESTINATION_ROUTING_KEY, rabbitmq_data[:key])
|
|
44
|
-
add_attribute(attributes, 'messaging.rabbitmq.queue', rabbitmq_data[:queue])
|
|
45
|
-
add_attribute(attributes, OpenTelemetry::SemConv::SERVER::SERVER_ADDRESS, rabbitmq_data[:address])
|
|
46
|
-
|
|
47
|
-
operation = rabbitmq_data[:sort] == 'publish' ? 'send' : 'receive'
|
|
48
|
-
add_attribute(attributes, OpenTelemetry::SemConv::Incubating::MESSAGING::MESSAGING_OPERATION_TYPE, operation)
|
|
49
|
-
end
|
|
63
|
+
def convert_rabbitmq_attributes(attributes, rabbitmq_data)
|
|
64
|
+
return unless rabbitmq_data
|
|
50
65
|
|
|
51
|
-
attributes
|
|
66
|
+
add_attribute(attributes, OpenTelemetry::SemConv::Incubating::MESSAGING::MESSAGING_SYSTEM, 'rabbitmq')
|
|
67
|
+
add_attribute(attributes, OpenTelemetry::SemConv::Incubating::MESSAGING::MESSAGING_DESTINATION_NAME,
|
|
68
|
+
rabbitmq_destination_name(rabbitmq_data))
|
|
69
|
+
add_attribute(attributes, OpenTelemetry::SemConv::Incubating::MESSAGING::MESSAGING_RABBITMQ_DESTINATION_ROUTING_KEY, rabbitmq_data[:key])
|
|
70
|
+
add_attribute(attributes, 'messaging.rabbitmq.queue', rabbitmq_data[:queue])
|
|
71
|
+
add_attribute(attributes, OpenTelemetry::SemConv::SERVER::SERVER_ADDRESS, extract_host(rabbitmq_data[:address]))
|
|
72
|
+
add_attribute(attributes, OpenTelemetry::SemConv::SERVER::SERVER_PORT, extract_port(rabbitmq_data[:address]))
|
|
73
|
+
add_attribute(attributes, OpenTelemetry::SemConv::Incubating::MESSAGING::MESSAGING_MESSAGE_BODY_SIZE, rabbitmq_data[:size])
|
|
74
|
+
|
|
75
|
+
operation = rabbitmq_data[:sort] == 'publish' ? 'send' : 'receive'
|
|
76
|
+
add_attribute(attributes, OpenTelemetry::SemConv::Incubating::MESSAGING::MESSAGING_OPERATION_TYPE, operation)
|
|
77
|
+
add_attribute(attributes, OpenTelemetry::SemConv::Incubating::MESSAGING::MESSAGING_OPERATION_NAME, rabbitmq_data[:sort])
|
|
52
78
|
end
|
|
53
79
|
|
|
54
|
-
|
|
80
|
+
def convert_kafka_attributes(attributes, kafka_data)
|
|
81
|
+
return unless kafka_data
|
|
82
|
+
|
|
83
|
+
add_attribute(attributes, OpenTelemetry::SemConv::Incubating::MESSAGING::MESSAGING_SYSTEM, 'kafka')
|
|
84
|
+
add_attribute(attributes, OpenTelemetry::SemConv::Incubating::MESSAGING::MESSAGING_DESTINATION_NAME, kafka_data[:service])
|
|
85
|
+
add_attribute(attributes, OpenTelemetry::SemConv::Incubating::MESSAGING::MESSAGING_OPERATION_NAME, kafka_data[:access])
|
|
86
|
+
add_attribute(attributes, OpenTelemetry::SemConv::Incubating::MESSAGING::MESSAGING_OPERATION_TYPE, kafka_data[:access])
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def extract_host(address)
|
|
90
|
+
return nil unless address
|
|
91
|
+
|
|
92
|
+
address.to_s.split(':').first
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def extract_port(address)
|
|
96
|
+
return nil unless address
|
|
97
|
+
|
|
98
|
+
port = address.to_s.split(':').last
|
|
99
|
+
port.to_i if port =~ /^\d+$/
|
|
100
|
+
end
|
|
55
101
|
|
|
56
102
|
# Build the composite destination name per spec:
|
|
57
103
|
# Producer (publish): "{exchange}:{key}" — omit absent parts
|
|
@@ -6,6 +6,7 @@ require_relative 'base_converter'
|
|
|
6
6
|
require 'opentelemetry/semconv/incubating/rpc'
|
|
7
7
|
require 'opentelemetry/semconv/incubating/code'
|
|
8
8
|
require 'opentelemetry/semconv/server'
|
|
9
|
+
require 'opentelemetry/semconv/network'
|
|
9
10
|
|
|
10
11
|
module Instana
|
|
11
12
|
module Exporter
|
|
@@ -48,10 +49,13 @@ module Instana
|
|
|
48
49
|
|
|
49
50
|
private
|
|
50
51
|
|
|
52
|
+
# gRPC status code mapping: 0 = OK for success, otherwise derive from error
|
|
53
|
+
GRPC_STATUS_CODE_OK = 0
|
|
54
|
+
|
|
51
55
|
# Convert gRPC span attributes
|
|
52
56
|
def convert_grpc_attributes(attributes, rpc_data)
|
|
53
57
|
# RPC system
|
|
54
|
-
add_attribute(attributes,
|
|
58
|
+
add_attribute(attributes, Instana::Exporter::Otlp::RPC_SYSTEM_ATTR, 'grpc')
|
|
55
59
|
|
|
56
60
|
# RPC service and method
|
|
57
61
|
if rpc_data[:call]
|
|
@@ -60,9 +64,20 @@ module Instana
|
|
|
60
64
|
add_attribute(attributes, OpenTelemetry::SemConv::Incubating::RPC::RPC_METHOD, method)
|
|
61
65
|
end
|
|
62
66
|
|
|
63
|
-
#
|
|
67
|
+
# Server host and port
|
|
64
68
|
add_attribute(attributes, OpenTelemetry::SemConv::SERVER::SERVER_ADDRESS, rpc_data[:host])
|
|
65
|
-
add_attribute(attributes, OpenTelemetry::SemConv::SERVER::
|
|
69
|
+
add_attribute(attributes, OpenTelemetry::SemConv::SERVER::SERVER_PORT, parse_port(rpc_data[:port]))
|
|
70
|
+
|
|
71
|
+
# Network peer address (peer.address → network.peer.address)
|
|
72
|
+
peer = rpc_data[:peer]
|
|
73
|
+
if peer
|
|
74
|
+
add_attribute(attributes, OpenTelemetry::SemConv::NETWORK::NETWORK_PEER_ADDRESS, peer[:address])
|
|
75
|
+
add_attribute(attributes, OpenTelemetry::SemConv::NETWORK::NETWORK_PEER_PORT, parse_port(peer[:port]))
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# gRPC status code (integer): 0 = OK for success spans
|
|
79
|
+
grpc_status = grpc_status_code(rpc_data)
|
|
80
|
+
add_attribute(attributes, OpenTelemetry::SemConv::Incubating::RPC::RPC_GRPC_STATUS_CODE, grpc_status)
|
|
66
81
|
|
|
67
82
|
# gRPC-specific attributes
|
|
68
83
|
add_attribute(attributes, 'rpc.grpc.call_type', rpc_data[:call_type])
|
|
@@ -71,7 +86,7 @@ module Instana
|
|
|
71
86
|
# Convert ActionCable span attributes
|
|
72
87
|
def convert_action_cable_attributes(attributes, rpc_data)
|
|
73
88
|
# RPC system
|
|
74
|
-
add_attribute(attributes,
|
|
89
|
+
add_attribute(attributes, Instana::Exporter::Otlp::RPC_SYSTEM_ATTR, 'actioncable')
|
|
75
90
|
|
|
76
91
|
# ActionCable-specific attributes
|
|
77
92
|
add_attribute(attributes, 'rails.actioncable.channel', rpc_data[:call])
|
|
@@ -96,6 +111,51 @@ module Instana
|
|
|
96
111
|
|
|
97
112
|
[parts[1], parts[2]]
|
|
98
113
|
end
|
|
114
|
+
|
|
115
|
+
# Parse port value to integer, returns nil if invalid or out of range
|
|
116
|
+
def parse_port(port)
|
|
117
|
+
return nil unless port
|
|
118
|
+
|
|
119
|
+
int_port = port.to_i
|
|
120
|
+
int_port if int_port >= 0 && int_port <= 65_535
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Map to gRPC status code integer.
|
|
124
|
+
# For successful spans (ec = 0) → 0 (OK).
|
|
125
|
+
# For error spans with a recognized gRPC status string in the error → map it.
|
|
126
|
+
# Otherwise → nil (omit the attribute).
|
|
127
|
+
GRPC_STATUS_CODES = {
|
|
128
|
+
'OK' => 0,
|
|
129
|
+
'CANCELLED' => 1,
|
|
130
|
+
'UNKNOWN' => 2,
|
|
131
|
+
'INVALID_ARGUMENT' => 3,
|
|
132
|
+
'DEADLINE_EXCEEDED' => 4,
|
|
133
|
+
'NOT_FOUND' => 5,
|
|
134
|
+
'ALREADY_EXISTS' => 6,
|
|
135
|
+
'PERMISSION_DENIED' => 7,
|
|
136
|
+
'RESOURCE_EXHAUSTED' => 8,
|
|
137
|
+
'FAILED_PRECONDITION' => 9,
|
|
138
|
+
'ABORTED' => 10,
|
|
139
|
+
'OUT_OF_RANGE' => 11,
|
|
140
|
+
'UNIMPLEMENTED' => 12,
|
|
141
|
+
'INTERNAL' => 13,
|
|
142
|
+
'UNAVAILABLE' => 14,
|
|
143
|
+
'DATA_LOSS' => 15,
|
|
144
|
+
'UNAUTHENTICATED' => 16
|
|
145
|
+
}.freeze
|
|
146
|
+
|
|
147
|
+
def grpc_status_code(rpc_data)
|
|
148
|
+
error_count = span[:ec].to_i
|
|
149
|
+
return GRPC_STATUS_CODE_OK if error_count.zero?
|
|
150
|
+
|
|
151
|
+
# Attempt to extract gRPC status string from error message
|
|
152
|
+
error_msg = rpc_data[:error].to_s
|
|
153
|
+
GRPC_STATUS_CODES.each do |name, code|
|
|
154
|
+
return code if error_msg.include?(name)
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
GRPC_STATUS_CODES['UNKNOWN']
|
|
158
|
+
end
|
|
99
159
|
end
|
|
100
160
|
end
|
|
101
161
|
end
|
data/lib/instana/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: instana
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.10.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Peter Giacomo Lombardo
|
|
@@ -416,7 +416,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
416
416
|
- !ruby/object:Gem::Version
|
|
417
417
|
version: '0'
|
|
418
418
|
requirements: []
|
|
419
|
-
rubygems_version: 4.0.
|
|
419
|
+
rubygems_version: 4.0.22
|
|
420
420
|
specification_version: 4
|
|
421
421
|
summary: Ruby Distributed Tracing & Metrics Sensor for Instana
|
|
422
422
|
test_files: []
|