Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
c9c5434
Initial commit
olegbespalov May 15, 2024
1a487f3
Skeleton structure from xk6 output template
olegbespalov May 15, 2024
46403a9
Basic CI
olegbespalov May 15, 2024
ae7671c
Adds CODEOWNERS
olegbespalov May 15, 2024
ddebd1a
Using common Makefile
olegbespalov May 15, 2024
42d054b
chore: go mod tidy
olegbespalov May 15, 2024
9f69fd4
Ignores local golangcilint config
olegbespalov May 15, 2024
9fb92af
Base OTEL docker-compose
olegbespalov May 15, 2024
8ddf863
Minimal working version
olegbespalov May 15, 2024
7083c18
Align config options with OTEL, HTTP exporter
olegbespalov May 23, 2024
6370428
Update k6's version
olegbespalov Jun 6, 2024
de62ccc
Refactor to metrics registry
olegbespalov May 23, 2024
52d135a
Implement Rate splitting
olegbespalov Jun 6, 2024
02e1c0d
Adjust dashboard
olegbespalov Jun 6, 2024
d0f4424
A proper gauge
olegbespalov Jun 6, 2024
8e51082
Fix demo dashboard
olegbespalov Jun 11, 2024
8585004
Rename template leftovers
olegbespalov Jun 13, 2024
1e26470
Config consolidation
olegbespalov Jun 13, 2024
f2a93ed
More test cases
olegbespalov Jun 13, 2024
edd1a97
Wrap validation error with the right exit code
olegbespalov Jun 13, 2024
b297321
Remove obsolete
olegbespalov Jun 13, 2024
4499201
Set default export interval as 10s
olegbespalov Jun 18, 2024
2ff1f89
Passing metrics unit when available
olegbespalov Jun 14, 2024
4cdf100
TLS configuration
olegbespalov Jun 14, 2024
62ac853
Headers configuration
olegbespalov Jun 14, 2024
da075ca
Downgrade gopkg.in/guregu/null.v3 to reflect k6
olegbespalov Jun 21, 2024
8049cf9
Merge pull request #17 from grafana/chore/downgrade-dependency
oleiade Jun 24, 2024
6a542f1
Downgrade afero to a version that frozen in k6 core
olegbespalov Jul 8, 2024
411cf08
Downgrade opentelemetry to reflect k6 core
olegbespalov Jul 8, 2024
7a50ee7
Bump k6 to v0.52
olegbespalov Jul 8, 2024
311844c
Downgrade go.opentelemetry.io/proto/otlp to reflect k6-core
olegbespalov Jul 8, 2024
9fc9761
Downgrade golang to reflect k6 core
olegbespalov Jul 9, 2024
98031f1
Error on scheme in http endpoint
mstoykov Aug 6, 2024
152e349
Update k6 to v0.53
olegbespalov Aug 16, 2024
4008a76
Using NewSchemaless to make dependency management easier
olegbespalov Aug 23, 2024
36c3be2
Update OTEL to v1.28.0
olegbespalov Aug 23, 2024
1893f39
Migrate to OTEL synchronous Float64Gauge
olegbespalov Aug 23, 2024
1b97bf3
Allow service.name otel env variable
TimotejKovacka Sep 29, 2024
133ea7f
Merge pull request #24 from TimotejKovacka/main
oleiade Oct 16, 2024
14cfd08
test(output): add integration tests
Nov 24, 2024
dc79ff2
Merge pull request #26 from TimotejKovacka/main
oleiade Dec 9, 2024
de3082c
Add 'internal/output/opentelemetry/' from commit 'dc79ff2430d29f77699…
olegbespalov Feb 19, 2025
6f7f6b0
output opentelemetry: cleanup unnsecessary files
olegbespalov Feb 19, 2025
72b7884
output opentelemetry: move to using the in k6 code
olegbespalov Feb 19, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 5 additions & 6 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ require (
github.com/gorilla/websocket v1.5.3
github.com/grafana/sobek v0.0.0-20241024150027-d91f02b05e9b
github.com/grafana/xk6-dashboard v0.7.5
github.com/grafana/xk6-output-opentelemetry v0.3.0
github.com/grafana/xk6-redis v0.3.3
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0
github.com/influxdata/influxdb1-client v0.0.0-20190402204710-8ff2fc3824fc
Expand All @@ -41,11 +40,16 @@ require (
github.com/stretchr/testify v1.10.0
github.com/tidwall/gjson v1.18.0
go.opentelemetry.io/otel v1.32.0
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.28.0
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.28.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.29.0
go.opentelemetry.io/otel/metric v1.32.0
go.opentelemetry.io/otel/sdk v1.32.0
go.opentelemetry.io/otel/sdk/metric v1.32.0
go.opentelemetry.io/otel/trace v1.32.0
go.opentelemetry.io/proto/otlp v1.3.1
go.uber.org/goleak v1.3.0
golang.org/x/crypto v0.33.0
golang.org/x/crypto/x509roots/fallback v0.0.0-20250210163342-e47973b1c108
Expand Down Expand Up @@ -88,11 +92,6 @@ require (
github.com/redis/go-redis/v9 v9.0.5 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.28.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.28.0 // indirect
go.opentelemetry.io/otel/metric v1.32.0 // indirect
go.opentelemetry.io/otel/sdk/metric v1.32.0 // indirect
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
golang.org/x/sys v0.30.0 // indirect
golang.org/x/text v0.22.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20241202173237-19429a94021a // indirect
Expand Down
2 changes: 0 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,6 @@ github.com/grafana/sobek v0.0.0-20241024150027-d91f02b05e9b h1:hzfIt1lf19Zx1jIYd
github.com/grafana/sobek v0.0.0-20241024150027-d91f02b05e9b/go.mod h1:FmcutBFPLiGgroH42I4/HBahv7GxVjODcVWFTw1ISes=
github.com/grafana/xk6-dashboard v0.7.5 h1:TcILyffT/Ea/XD7xG1jMA5lwtusOPRbEQsQDHmO30Mk=
github.com/grafana/xk6-dashboard v0.7.5/go.mod h1:Y75F8xmgCraKT+pBzFH6me9AyH5PkXD+Bxo1dm6Il/M=
github.com/grafana/xk6-output-opentelemetry v0.3.0 h1:dmclGBFtFVRJijqLncpu2dKVIIvx1GS3y6sQGg4Khl8=
github.com/grafana/xk6-output-opentelemetry v0.3.0/go.mod h1:5uUg0J2dxrw+DkC9fCsfiKv2jTpccn7nz6vGmRUr4f8=
github.com/grafana/xk6-redis v0.3.3 h1:9QiS4OUjYMzvriGzbqrhCn9i/kENmCkibZE+xCJSdPk=
github.com/grafana/xk6-redis v0.3.3/go.mod h1:YL1qfBZXW4o2aAF6/gRa/N9oGoumUg7cJzzCHLxoCOw=
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI=
Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/outputs.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ import (
"go.k6.io/k6/internal/output/cloud"
"go.k6.io/k6/internal/output/influxdb"
"go.k6.io/k6/internal/output/json"
"go.k6.io/k6/internal/output/opentelemetry"
"go.k6.io/k6/internal/output/prometheusrw/remotewrite"
"go.k6.io/k6/lib"
"go.k6.io/k6/output"
"go.k6.io/k6/output/csv"

"github.com/grafana/xk6-dashboard/dashboard"
"github.com/grafana/xk6-output-opentelemetry/pkg/opentelemetry"
)

// builtinOutput marks the available builtin outputs.
Expand Down
204 changes: 204 additions & 0 deletions internal/output/opentelemetry/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
package opentelemetry

import (
"encoding/json"
"testing"
"time"

"github.com/stretchr/testify/require"
k6Const "go.k6.io/k6/lib/consts"
"go.k6.io/k6/lib/types"
"gopkg.in/guregu/null.v3"
)

func TestConfig(t *testing.T) {
t.Parallel()
// TODO: add more cases
testCases := map[string]struct {
jsonRaw json.RawMessage
env map[string]string
arg string
expectedConfig Config
err string
}{
"default": {
expectedConfig: Config{
ServiceName: null.StringFrom("k6"),
ServiceVersion: null.StringFrom(k6Const.Version),
ExporterType: null.StringFrom(grpcExporterType),
HTTPExporterInsecure: null.NewBool(false, true),
HTTPExporterEndpoint: null.StringFrom("localhost:4318"),
HTTPExporterURLPath: null.StringFrom("/v1/metrics"),
GRPCExporterInsecure: null.NewBool(false, true),
GRPCExporterEndpoint: null.StringFrom("localhost:4317"),
ExportInterval: types.NullDurationFrom(10 * time.Second),
FlushInterval: types.NullDurationFrom(1 * time.Second),
},
},

"environment success merge": {
env: map[string]string{"K6_OTEL_GRPC_EXPORTER_ENDPOINT": "else", "K6_OTEL_EXPORT_INTERVAL": "4ms"},
expectedConfig: Config{
ServiceName: null.StringFrom("k6"),
ServiceVersion: null.StringFrom(k6Const.Version),
ExporterType: null.StringFrom(grpcExporterType),
HTTPExporterInsecure: null.NewBool(false, true),
HTTPExporterEndpoint: null.StringFrom("localhost:4318"),
HTTPExporterURLPath: null.StringFrom("/v1/metrics"),
GRPCExporterInsecure: null.NewBool(false, true),
GRPCExporterEndpoint: null.StringFrom("else"),
ExportInterval: types.NullDurationFrom(4 * time.Millisecond),
FlushInterval: types.NullDurationFrom(1 * time.Second),
},
},

"environment complete overwrite": {
env: map[string]string{
"K6_OTEL_SERVICE_NAME": "foo",
"K6_OTEL_SERVICE_VERSION": "v0.0.99",
"K6_OTEL_EXPORTER_TYPE": "http",
"K6_OTEL_EXPORT_INTERVAL": "4ms",
"K6_OTEL_HTTP_EXPORTER_INSECURE": "true",
"K6_OTEL_HTTP_EXPORTER_ENDPOINT": "localhost:5555",
"K6_OTEL_HTTP_EXPORTER_URL_PATH": "/foo/bar",
"K6_OTEL_GRPC_EXPORTER_INSECURE": "true",
"K6_OTEL_GRPC_EXPORTER_ENDPOINT": "else",
"K6_OTEL_FLUSH_INTERVAL": "13s",
"K6_OTEL_TLS_INSECURE_SKIP_VERIFY": "true",
"K6_OTEL_TLS_CERTIFICATE": "cert_path",
"K6_OTEL_TLS_CLIENT_CERTIFICATE": "client_cert_path",
"K6_OTEL_TLS_CLIENT_KEY": "client_key_path",
"K6_OTEL_HEADERS": "key1=value1,key2=value2",
},
expectedConfig: Config{
ServiceName: null.StringFrom("foo"),
ServiceVersion: null.StringFrom("v0.0.99"),
ExporterType: null.StringFrom(httpExporterType),
ExportInterval: types.NullDurationFrom(4 * time.Millisecond),
HTTPExporterInsecure: null.NewBool(true, true),
HTTPExporterEndpoint: null.StringFrom("localhost:5555"),
HTTPExporterURLPath: null.StringFrom("/foo/bar"),
GRPCExporterInsecure: null.NewBool(true, true),
GRPCExporterEndpoint: null.StringFrom("else"),
FlushInterval: types.NullDurationFrom(13 * time.Second),
TLSInsecureSkipVerify: null.NewBool(true, true),
TLSCertificate: null.StringFrom("cert_path"),
TLSClientCertificate: null.StringFrom("client_cert_path"),
TLSClientKey: null.StringFrom("client_key_path"),
Headers: null.StringFrom("key1=value1,key2=value2"),
},
},

"OTEL environment variables": {
env: map[string]string{
"OTEL_SERVICE_NAME": "otel-service",
},
expectedConfig: Config{
ServiceName: null.StringFrom("otel-service"),
ServiceVersion: null.StringFrom(k6Const.Version),
ExporterType: null.StringFrom(grpcExporterType),
HTTPExporterInsecure: null.NewBool(false, true),
HTTPExporterEndpoint: null.StringFrom("localhost:4318"),
HTTPExporterURLPath: null.StringFrom("/v1/metrics"),
GRPCExporterInsecure: null.NewBool(false, true),
GRPCExporterEndpoint: null.StringFrom("localhost:4317"),
ExportInterval: types.NullDurationFrom(10 * time.Second),
FlushInterval: types.NullDurationFrom(1 * time.Second),
},
},

"JSON complete overwrite": {
jsonRaw: json.RawMessage(
`{` +
`"serviceName":"bar",` +
`"serviceVersion":"v2.0.99",` +
`"exporterType":"http",` +
`"exportInterval":"15ms",` +
`"httpExporterInsecure":true,` +
`"httpExporterEndpoint":"localhost:5555",` +
`"httpExporterURLPath":"/foo/bar",` +
`"grpcExporterInsecure":true,` +
`"grpcExporterEndpoint":"else",` +
`"flushInterval":"13s",` +
`"tlsInsecureSkipVerify":true,` +
`"tlsCertificate":"cert_path",` +
`"tlsClientCertificate":"client_cert_path",` +
`"tlsClientKey":"client_key_path",` +
`"headers":"key1=value1,key2=value2"` +
`}`,
),
expectedConfig: Config{
ServiceName: null.StringFrom("bar"),
ServiceVersion: null.StringFrom("v2.0.99"),
ExporterType: null.StringFrom(httpExporterType),
ExportInterval: types.NullDurationFrom(15 * time.Millisecond),
HTTPExporterInsecure: null.NewBool(true, true),
HTTPExporterEndpoint: null.StringFrom("localhost:5555"),
HTTPExporterURLPath: null.StringFrom("/foo/bar"),
GRPCExporterInsecure: null.NewBool(true, true),
GRPCExporterEndpoint: null.StringFrom("else"),
FlushInterval: types.NullDurationFrom(13 * time.Second),
TLSInsecureSkipVerify: null.NewBool(true, true),
TLSCertificate: null.StringFrom("cert_path"),
TLSClientCertificate: null.StringFrom("client_cert_path"),
TLSClientKey: null.StringFrom("client_key_path"),
Headers: null.StringFrom("key1=value1,key2=value2"),
},
},

"JSON success merge": {
jsonRaw: json.RawMessage(`{"exporterType":"http","httpExporterEndpoint":"localhost:5566","httpExporterURLPath":"/lorem/ipsum", "exportInterval":"15ms"}`),
expectedConfig: Config{
ServiceName: null.StringFrom("k6"),
ServiceVersion: null.StringFrom(k6Const.Version),
ExporterType: null.StringFrom(httpExporterType),
HTTPExporterInsecure: null.NewBool(false, true),
HTTPExporterEndpoint: null.StringFrom("localhost:5566"),
HTTPExporterURLPath: null.StringFrom("/lorem/ipsum"),
GRPCExporterInsecure: null.NewBool(false, true), // default
GRPCExporterEndpoint: null.StringFrom("localhost:4317"), // default
ExportInterval: types.NullDurationFrom(15 * time.Millisecond),
FlushInterval: types.NullDurationFrom(1 * time.Second),
},
},
"no scheme in http exporter": {
jsonRaw: json.RawMessage(`{"exporterType":"http","httpExporterEndpoint":"http://localhost:5566","httpExporterURLPath":"/lorem/ipsum", "exportInterval":"15ms"}`),
err: `config: HTTP exporter endpoint must only be host and port, no scheme`,
},

"early error env": {
env: map[string]string{"K6_OTEL_GRPC_EXPORTER_ENDPOINT": "else", "K6_OTEL_EXPORT_INTERVAL": "4something"},
err: `time: unknown unit "something" in duration "4something"`,
},

"early error JSON": {
jsonRaw: json.RawMessage(`{"exportInterval":"4something"}`),
err: `time: unknown unit "something" in duration "4something"`,
},

"unsupported receiver type": {
env: map[string]string{"K6_OTEL_GRPC_EXPORTER_ENDPOINT": "else", "K6_OTEL_EXPORT_INTERVAL": "4m", "K6_OTEL_EXPORTER_TYPE": "socket"},
err: `error validating OpenTelemetry output config: unsupported exporter type "socket", currently only "grpc" and "http" are supported`,
},

"missing required": {
jsonRaw: json.RawMessage(`{"exporterType":"http","httpExporterEndpoint":"","httpExporterURLPath":"/lorem/ipsum"}`),
err: `HTTP exporter endpoint is required`,
},
}

for name, testCase := range testCases {
testCase := testCase
t.Run(name, func(t *testing.T) {
t.Parallel()
config, err := GetConsolidatedConfig(testCase.jsonRaw, testCase.env)
if testCase.err != "" {
require.Error(t, err)
require.Contains(t, err.Error(), testCase.err)
return
}
require.NoError(t, err)
require.Equal(t, testCase.expectedConfig, config)
})
}
}
Loading
Loading