Skip to content

Commit e44c182

Browse files
README update
1 parent f5c50bd commit e44c182

5 files changed

Lines changed: 75 additions & 46 deletions

File tree

receiver/restapireceiver/README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@ The REST API receiver is a generic receiver that can pull data from any REST API
44

55
## Supported Pipelines
66

7+
Alpha:
78
- Logs
89
- Metrics
910

11+
**Due to the wide range of use cases possible for this receiver, this component offers a best-effort integration with common API patterns, but may not completely align with every REST API.**
12+
1013
## How It Works
1114

1215
1. The receiver polls a configured REST API endpoint at a specified interval.
@@ -78,6 +81,8 @@ Use `auth_mode: none` for public APIs that don't require authentication. No addi
7881

7982
#### Akamai EdgeGrid
8083

84+
**The Akamai API requires an enterprise license. This authentication method has not been tested against an Akamai API.**
85+
8186
| Field | Type | Default | Required | Description |
8287
|-------|------|---------|----------|-------------|
8388
| `akamai_access_token` | string || `true` | Akamai EdgeGrid access token |

receiver/restapireceiver/integration_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,9 @@ func TestIntegration_EndToEnd_Metrics(t *testing.T) {
114114
},
115115
MaxPollInterval: 100 * time.Millisecond,
116116
ClientConfig: confighttp.ClientConfig{},
117+
Metrics: MetricsConfig{
118+
NameField: "metric",
119+
},
117120
}
118121

119122
sink := new(consumertest.MetricsSink)

receiver/restapireceiver/metrics.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,19 @@ func convertJSONToMetrics(data []map[string]any, cfg *MetricsConfig, logger *zap
3939
continue
4040
}
4141

42-
// Extract metric name (defaults to "restapi.metric")
43-
metricName := "restapi.metric"
42+
// Extract metric name (required)
43+
metricName := ""
4444
if cfg.NameField != "" {
4545
if nameVal, ok := item[cfg.NameField]; ok {
4646
if nameStr, ok := nameVal.(string); ok && nameStr != "" {
4747
metricName = nameStr
4848
}
4949
}
5050
}
51+
if metricName == "" {
52+
logger.Warn("skipping item without metric name", zap.String("name_field", cfg.NameField), zap.Any("item", item))
53+
continue
54+
}
5155

5256
// Extract metric description (defaults to "Metric from REST API")
5357
metricDescription := "Metric from REST API"

receiver/restapireceiver/metrics_test.go

Lines changed: 58 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ func TestConvertJSONToMetrics_SimpleArray(t *testing.T) {
3030
}
3131

3232
logger := zap.NewNop()
33-
cfg := &MetricsConfig{}
33+
cfg := &MetricsConfig{
34+
NameField: "name",
35+
}
3436
metrics := convertJSONToMetrics(data, cfg, logger)
3537

3638
require.Equal(t, 1, metrics.ResourceMetrics().Len())
@@ -42,21 +44,17 @@ func TestConvertJSONToMetrics_SimpleArray(t *testing.T) {
4244

4345
// Check first metric
4446
metric1 := scopeMetrics.Metrics().At(0)
45-
require.Equal(t, "restapi.metric", metric1.Name())
47+
require.Equal(t, "metric1", metric1.Name())
4648
require.Equal(t, pmetric.MetricTypeGauge, metric1.Type())
4749

4850
gauge := metric1.Gauge()
4951
require.Equal(t, 1, gauge.DataPoints().Len())
5052
dp1 := gauge.DataPoints().At(0)
5153
require.Equal(t, 42.5, dp1.DoubleValue())
5254

53-
// Check attributes
54-
attrs1 := dp1.Attributes()
55-
require.Equal(t, "metric1", attrs1.AsRaw()["name"])
56-
5755
// Check second metric
5856
metric2 := scopeMetrics.Metrics().At(1)
59-
require.Equal(t, "restapi.metric", metric2.Name())
57+
require.Equal(t, "metric2", metric2.Name())
6058
gauge2 := metric2.Gauge()
6159
require.Equal(t, 1, gauge2.DataPoints().Len())
6260
dp2 := gauge2.DataPoints().At(0)
@@ -76,13 +74,15 @@ func TestConvertJSONToMetrics_EmptyArray(t *testing.T) {
7674

7775
func TestConvertJSONToMetrics_WithNumericValue(t *testing.T) {
7876
data := []map[string]any{
79-
{"value": 42, "unit": "bytes"},
80-
{"value": 99.99, "unit": "percent"},
81-
{"value": int64(1000), "unit": "count"},
77+
{"value": 42, "unit": "bytes", "name": "metric1"},
78+
{"value": 99.99, "unit": "percent", "name": "metric2"},
79+
{"value": int64(1000), "unit": "count", "name": "metric3"},
8280
}
8381

8482
logger := zap.NewNop()
85-
cfg := &MetricsConfig{}
83+
cfg := &MetricsConfig{
84+
NameField: "name",
85+
}
8686
metrics := convertJSONToMetrics(data, cfg, logger)
8787

8888
require.Equal(t, 3, metrics.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().Len())
@@ -111,6 +111,7 @@ func TestConvertJSONToMetrics_WithAttributes(t *testing.T) {
111111
data := []map[string]any{
112112
{
113113
"value": 50.0,
114+
"name": "test.metric",
114115
"service": "api",
115116
"env": "prod",
116117
"region": "us-east-1",
@@ -119,7 +120,9 @@ func TestConvertJSONToMetrics_WithAttributes(t *testing.T) {
119120
}
120121

121122
logger := zap.NewNop()
122-
cfg := &MetricsConfig{}
123+
cfg := &MetricsConfig{
124+
NameField: "name",
125+
}
123126
metrics := convertJSONToMetrics(data, cfg, logger)
124127

125128
metric := metrics.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(0)
@@ -141,7 +144,9 @@ func TestConvertJSONToMetrics_NoValueField(t *testing.T) {
141144
}
142145

143146
logger := zap.NewNop()
144-
cfg := &MetricsConfig{}
147+
cfg := &MetricsConfig{
148+
NameField: "name",
149+
}
145150
metrics := convertJSONToMetrics(data, cfg, logger)
146151

147152
// Should still create metrics, using first numeric field as value
@@ -160,7 +165,9 @@ func TestConvertJSONToMetrics_NoNumericValue(t *testing.T) {
160165
}
161166

162167
logger := zap.NewNop()
163-
cfg := &MetricsConfig{}
168+
cfg := &MetricsConfig{
169+
NameField: "name",
170+
}
164171
metrics := convertJSONToMetrics(data, cfg, logger)
165172

166173
// Should skip items without numeric values
@@ -169,11 +176,13 @@ func TestConvertJSONToMetrics_NoNumericValue(t *testing.T) {
169176

170177
func TestConvertJSONToMetrics_WithTimestamp(t *testing.T) {
171178
data := []map[string]any{
172-
{"value": 42.0, "timestamp": "2023-01-01T00:00:00Z"},
179+
{"value": 42.0, "name": "test.metric", "timestamp": "2023-01-01T00:00:00Z"},
173180
}
174181

175182
logger := zap.NewNop()
176-
cfg := &MetricsConfig{}
183+
cfg := &MetricsConfig{
184+
NameField: "name",
185+
}
177186
metrics := convertJSONToMetrics(data, cfg, logger)
178187

179188
metric := metrics.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(0)
@@ -186,15 +195,17 @@ func TestConvertJSONToMetrics_WithTimestamp(t *testing.T) {
186195

187196
func TestConvertJSONToMetrics_MultipleMetrics(t *testing.T) {
188197
data := []map[string]any{
189-
{"value": 1.0, "id": "1"},
190-
{"value": 2.0, "id": "2"},
191-
{"value": 3.0, "id": "3"},
192-
{"value": 4.0, "id": "4"},
193-
{"value": 5.0, "id": "5"},
198+
{"value": 1.0, "name": "metric.1", "id": "1"},
199+
{"value": 2.0, "name": "metric.2", "id": "2"},
200+
{"value": 3.0, "name": "metric.3", "id": "3"},
201+
{"value": 4.0, "name": "metric.4", "id": "4"},
202+
{"value": 5.0, "name": "metric.5", "id": "5"},
194203
}
195204

196205
logger := zap.NewNop()
197-
cfg := &MetricsConfig{}
206+
cfg := &MetricsConfig{
207+
NameField: "name",
208+
}
198209
metrics := convertJSONToMetrics(data, cfg, logger)
199210

200211
require.Equal(t, 5, metrics.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().Len())
@@ -213,6 +224,7 @@ func TestConvertJSONToMetrics_WithNestedFields(t *testing.T) {
213224
data := []map[string]any{
214225
{
215226
"value": 42.0,
227+
"name": "test.metric",
216228
"metadata": map[string]any{
217229
"source": "api",
218230
"env": "prod",
@@ -221,7 +233,9 @@ func TestConvertJSONToMetrics_WithNestedFields(t *testing.T) {
221233
}
222234

223235
logger := zap.NewNop()
224-
cfg := &MetricsConfig{}
236+
cfg := &MetricsConfig{
237+
NameField: "name",
238+
}
225239
metrics := convertJSONToMetrics(data, cfg, logger)
226240

227241
metric := metrics.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(0)
@@ -260,11 +274,12 @@ func TestConvertJSONToMetrics_WithCustomNameField(t *testing.T) {
260274

261275
func TestConvertJSONToMetrics_WithCustomDescriptionField(t *testing.T) {
262276
data := []map[string]any{
263-
{"value": 42.5, "metric_desc": "CPU usage percentage", "host": "server1"},
277+
{"value": 42.5, "name": "cpu.usage", "metric_desc": "CPU usage percentage", "host": "server1"},
264278
}
265279

266280
logger := zap.NewNop()
267281
cfg := &MetricsConfig{
282+
NameField: "name",
268283
DescriptionField: "metric_desc",
269284
}
270285
metrics := convertJSONToMetrics(data, cfg, logger)
@@ -275,13 +290,14 @@ func TestConvertJSONToMetrics_WithCustomDescriptionField(t *testing.T) {
275290

276291
func TestConvertJSONToMetrics_WithCustomTypeField(t *testing.T) {
277292
data := []map[string]any{
278-
{"value": 42.5, "metric_type": "sum", "host": "server1"},
279-
{"value": 100.0, "metric_type": "gauge", "host": "server2"},
280-
{"value": 75.0, "metric_type": "histogram", "host": "server3"},
293+
{"value": 42.5, "name": "metric1", "metric_type": "sum", "host": "server1"},
294+
{"value": 100.0, "name": "metric2", "metric_type": "gauge", "host": "server2"},
295+
{"value": 75.0, "name": "metric3", "metric_type": "histogram", "host": "server3"},
281296
}
282297

283298
logger := zap.NewNop()
284299
cfg := &MetricsConfig{
300+
NameField: "name",
285301
TypeField: "metric_type",
286302
}
287303
metrics := convertJSONToMetrics(data, cfg, logger)
@@ -307,12 +323,13 @@ func TestConvertJSONToMetrics_WithCustomTypeField(t *testing.T) {
307323

308324
func TestConvertJSONToMetrics_WithUnitField(t *testing.T) {
309325
data := []map[string]any{
310-
{"value": 42.5, "unit": "bytes", "host": "server1"},
311-
{"value": 100.0, "unit": "percent", "host": "server2"},
326+
{"value": 42.5, "name": "metric1", "unit": "bytes", "host": "server1"},
327+
{"value": 100.0, "name": "metric2", "unit": "percent", "host": "server2"},
312328
}
313329

314330
logger := zap.NewNop()
315331
cfg := &MetricsConfig{
332+
NameField: "name",
316333
UnitField: "unit",
317334
}
318335
metrics := convertJSONToMetrics(data, cfg, logger)
@@ -329,7 +346,7 @@ func TestConvertJSONToMetrics_WithUnitField(t *testing.T) {
329346
require.Equal(t, "percent", metric2.Unit())
330347
}
331348

332-
func TestConvertJSONToMetrics_WithDefaults(t *testing.T) {
349+
func TestConvertJSONToMetrics_WithoutNameField(t *testing.T) {
333350
data := []map[string]any{
334351
{"value": 42.5, "host": "server1"},
335352
{"value": 100.0, "host": "server2"},
@@ -340,14 +357,8 @@ func TestConvertJSONToMetrics_WithDefaults(t *testing.T) {
340357
metrics := convertJSONToMetrics(data, cfg, logger)
341358

342359
scopeMetrics := metrics.ResourceMetrics().At(0).ScopeMetrics().At(0)
343-
require.Equal(t, 2, scopeMetrics.Metrics().Len())
344-
345-
// Check that hardcoded defaults are used
346-
metric1 := scopeMetrics.Metrics().At(0)
347-
require.Equal(t, "restapi.metric", metric1.Name())
348-
require.Equal(t, "Metric from REST API", metric1.Description())
349-
require.Equal(t, pmetric.MetricTypeGauge, metric1.Type())
350-
require.Equal(t, "", metric1.Unit())
360+
// Metrics without a name field should be dropped
361+
require.Equal(t, 0, scopeMetrics.Metrics().Len())
351362
}
352363

353364
func TestConvertJSONToMetrics_FieldOverridesDefaults(t *testing.T) {
@@ -416,12 +427,13 @@ func TestConvertJSONToMetrics_AllFieldsConfigured(t *testing.T) {
416427

417428
func TestConvertJSONToMetrics_WithMonotonicField(t *testing.T) {
418429
data := []map[string]any{
419-
{"value": 100.0, "metric_type": "sum", "is_monotonic": true, "host": "server1"},
420-
{"value": 50.0, "metric_type": "sum", "is_monotonic": false, "host": "server2"},
430+
{"value": 100.0, "name": "metric1", "metric_type": "sum", "is_monotonic": true, "host": "server1"},
431+
{"value": 50.0, "name": "metric2", "metric_type": "sum", "is_monotonic": false, "host": "server2"},
421432
}
422433

423434
logger := zap.NewNop()
424435
cfg := &MetricsConfig{
436+
NameField: "name",
425437
TypeField: "metric_type",
426438
MonotonicField: "is_monotonic",
427439
}
@@ -450,13 +462,14 @@ func TestConvertJSONToMetrics_WithMonotonicField(t *testing.T) {
450462

451463
func TestConvertJSONToMetrics_WithAggregationTemporalityField(t *testing.T) {
452464
data := []map[string]any{
453-
{"value": 100.0, "metric_type": "sum", "aggregation": "cumulative", "host": "server1"},
454-
{"value": 50.0, "metric_type": "sum", "aggregation": "delta", "host": "server2"},
455-
{"value": 75.0, "metric_type": "histogram", "aggregation": "delta", "host": "server3"},
465+
{"value": 100.0, "name": "metric1", "metric_type": "sum", "aggregation": "cumulative", "host": "server1"},
466+
{"value": 50.0, "name": "metric2", "metric_type": "sum", "aggregation": "delta", "host": "server2"},
467+
{"value": 75.0, "name": "metric3", "metric_type": "histogram", "aggregation": "delta", "host": "server3"},
456468
}
457469

458470
logger := zap.NewNop()
459471
cfg := &MetricsConfig{
472+
NameField: "name",
460473
TypeField: "metric_type",
461474
AggregationTemporalityField: "aggregation",
462475
}
@@ -541,11 +554,12 @@ func TestConvertJSONToMetrics_SumWithAllProperties(t *testing.T) {
541554

542555
func TestConvertJSONToMetrics_DefaultMonotonicAndAggregation(t *testing.T) {
543556
data := []map[string]any{
544-
{"value": 100.0, "metric_type": "sum", "host": "server1"},
557+
{"value": 100.0, "name": "test.metric", "metric_type": "sum", "host": "server1"},
545558
}
546559

547560
logger := zap.NewNop()
548561
cfg := &MetricsConfig{
562+
NameField: "name",
549563
TypeField: "metric_type",
550564
}
551565
metrics := convertJSONToMetrics(data, cfg, logger)

receiver/restapireceiver/receiver_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,9 @@ func TestRESTAPIMetricsReceiver_StartShutdown(t *testing.T) {
9898
},
9999
MaxPollInterval: 100 * time.Millisecond,
100100
ClientConfig: confighttp.ClientConfig{},
101+
Metrics: MetricsConfig{
102+
NameField: "name",
103+
},
101104
}
102105

103106
sink := new(consumertest.MetricsSink)

0 commit comments

Comments
 (0)