Skip to content

Commit

Permalink
✨ add metrics for elasticsearch, fiberv2 and mongo (#278) (#290)
Browse files Browse the repository at this point in the history
  • Loading branch information
martinyonatann authored Jan 16, 2025
1 parent 6fa1629 commit 4485e2f
Show file tree
Hide file tree
Showing 15 changed files with 391 additions and 25 deletions.
5 changes: 5 additions & 0 deletions pkg/inst-api/instrumenter/span_suppressor.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package instrumenter

import (
"context"

"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api/utils"

"go.opentelemetry.io/otel/attribute"
Expand All @@ -31,6 +32,8 @@ var scopeKey = map[string]attribute.Key{
utils.NET_HTTP_SERVER_SCOPE_NAME: utils.HTTP_SERVER_KEY,
utils.HERTZ_HTTP_CLIENT_SCOPE_NAME: utils.HTTP_CLIENT_KEY,
utils.HERTZ_HTTP_SERVER_SCOPE_NAME: utils.HTTP_SERVER_KEY,
utils.FIBER_V2_SERVER_SCOPE_NAME: utils.HTTP_SERVER_KEY,
utils.ELASTICSEARCH_SCOPE_NAME: utils.HTTP_CLIENT_KEY,

// grpc
utils.GRPC_CLIENT_SCOPE_NAME: utils.RPC_CLIENT_KEY,
Expand All @@ -53,6 +56,8 @@ var kindKey = map[string]trace.SpanKind{
utils.NET_HTTP_SERVER_SCOPE_NAME: trace.SpanKindServer,
utils.HERTZ_HTTP_CLIENT_SCOPE_NAME: trace.SpanKindClient,
utils.HERTZ_HTTP_SERVER_SCOPE_NAME: trace.SpanKindServer,
utils.FIBER_V2_SERVER_SCOPE_NAME: trace.SpanKindServer,
utils.ELASTICSEARCH_SCOPE_NAME: trace.SpanKindClient,

// grpc
utils.GRPC_CLIENT_SCOPE_NAME: trace.SpanKindClient,
Expand Down
2 changes: 2 additions & 0 deletions pkg/rules/elasticsearch/es_otel_instrumenter.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package elasticsearch

import (
"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api-semconv/instrumenter/db"
"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api-semconv/instrumenter/http"
"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api/instrumenter"
"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api/utils"
"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api/version"
Expand Down Expand Up @@ -49,6 +50,7 @@ func BuildElasticSearchInstrumenter() instrumenter.Instrumenter[*esRequest, inte
builder := instrumenter.Builder[*esRequest, any]{}
getter := elasticSearchGetter{}
return builder.Init().SetSpanNameExtractor(&db.DBSpanNameExtractor[*esRequest]{Getter: elasticSearchGetter{}}).SetSpanKindExtractor(&instrumenter.AlwaysClientExtractor[*esRequest]{}).
AddOperationListeners(http.HttpServerMetrics("elasticsearch.client")).
SetInstrumentationScope(instrumentation.Scope{
Name: utils.ELASTICSEARCH_SCOPE_NAME,
Version: version.Tag,
Expand Down
9 changes: 5 additions & 4 deletions pkg/rules/fiberv2/fiberv2_otel_instrumenter.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@
package fiberv2

import (
"strconv"

"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api/utils"
"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api/version"
"go.opentelemetry.io/otel/sdk/instrumentation"
"strconv"

"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api-semconv/instrumenter/http"
"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api-semconv/instrumenter/net"
Expand Down Expand Up @@ -73,11 +74,10 @@ func (n fiberv2ServerAttrsGetter) GetNetworkTransport(request *fiberv2Request, r
return "tcp"
}
func (n fiberv2ServerAttrsGetter) GetNetworkProtocolName(request *fiberv2Request, response *fiberv2Response) string {
if request.isTls == false {
if !request.isTls {
return "http"
} else {
return "https"
}
return "https"
}
func (n fiberv2ServerAttrsGetter) GetNetworkProtocolVersion(request *fiberv2Request, response *fiberv2Response) string {
return ""
Expand Down Expand Up @@ -128,6 +128,7 @@ func BuildFiberV2ServerOtelInstrumenter() *instrumenter.PropagatingFromUpstreamI
networkExtractor := net.NetworkAttrsExtractor[*fiberv2Request, *fiberv2Response, fiberv2ServerAttrsGetter]{Getter: serverGetter}
urlExtractor := net.UrlAttrsExtractor[*fiberv2Request, *fiberv2Response, fiberv2ServerAttrsGetter]{Getter: serverGetter}
return builder.Init().SetSpanStatusExtractor(http.HttpServerSpanStatusExtractor[*fiberv2Request, *fiberv2Response]{Getter: serverGetter}).SetSpanNameExtractor(&http.HttpServerSpanNameExtractor[*fiberv2Request, *fiberv2Response]{Getter: serverGetter}).
AddOperationListeners(http.HttpServerMetrics("fiberv2.server")).
SetSpanKindExtractor(&instrumenter.AlwaysServerExtractor[*fiberv2Request]{}).
SetInstrumentationScope(instrumentation.Scope{
Name: utils.FIBER_V2_SERVER_SCOPE_NAME,
Expand Down
8 changes: 4 additions & 4 deletions pkg/rules/http/net_http_otel_instrumenter.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@
package http

import (
"strconv"

"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api/utils"
"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api/version"
"go.opentelemetry.io/otel/sdk/instrumentation"
"strconv"

"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api-semconv/instrumenter/http"
"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api-semconv/instrumenter/net"
Expand Down Expand Up @@ -163,11 +164,10 @@ func (n netHttpServerAttrsGetter) GetNetworkTransport(request *netHttpRequest, r
}

func (n netHttpServerAttrsGetter) GetNetworkProtocolName(request *netHttpRequest, response *netHttpResponse) string {
if request.isTls == false {
if !request.isTls {
return "http"
} else {
return "https"
}
return "https"
}

func (n netHttpServerAttrsGetter) GetNetworkProtocolVersion(request *netHttpRequest, response *netHttpResponse) string {
Expand Down
1 change: 1 addition & 0 deletions pkg/rules/mongo/mongo_otel_instrumenter.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ func (m *mongoSpanNameExtractor) Extract(request mongoRequest) string {
func BuildMongoOtelInstrumenter() instrumenter.Instrumenter[mongoRequest, interface{}] {
builder := instrumenter.Builder[mongoRequest, interface{}]{}
return builder.Init().SetSpanNameExtractor(&mongoSpanNameExtractor{}).
AddOperationListeners(db.DbClientMetrics("nosql.mongo")).
SetSpanKindExtractor(&mongoSpanKindExtractor{}).
SetInstrumentationScope(instrumentation.Scope{
Name: utils.MONGO_SCOPE_NAME,
Expand Down
68 changes: 68 additions & 0 deletions test/elasticsearch/v8.4.0/test_es_metrics.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Copyright (c) 2024 Alibaba Group Holding Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
"strconv"
"time"

"log"
"os"

"github.com/alibaba/opentelemetry-go-auto-instrumentation/test/verifier"
"github.com/elastic/go-elasticsearch/v8"
"go.opentelemetry.io/otel/sdk/metric/metricdata"
)

var (
client *elasticsearch.Client
url = "http://127.0.0.1:" + os.Getenv("OTEL_ES_PORT")
)

func main() {
port, err := strconv.Atoi(os.Getenv("OTEL_ES_PORT"))
if err != nil {
panic(err)
}

client, err = elasticsearch.NewClient(elasticsearch.Config{
Addresses: []string{url},
Password: "123456",
Username: "elastic",
})
if err != nil {
panic(err)
}

// creating an index
_, err = client.Indices.Create("my_index")
if err != nil {
log.Printf("failed to create index %v\n", err)
}

time.Sleep(3 * time.Second)
verifier.WaitAndAssertMetrics(map[string]func(metricdata.ResourceMetrics){
"http.client.request.duration": func(mrs metricdata.ResourceMetrics) {
if len(mrs.ScopeMetrics) <= 0 {
panic("No http.client.request.duration metrics received!")
}
point := mrs.ScopeMetrics[0].Metrics[0].Data.(metricdata.Histogram[float64])
if point.DataPoints[0].Count <= 0 {
panic("http.client.request.duration metrics count is not positive, actually " + strconv.Itoa(int(point.DataPoints[0].Count)))
}
verifier.VerifyHttpClientMetricsAttributes(point.DataPoints[0].Attributes.ToSlice(), "PUT", "", "", "http", "1.1", port, 200)
},
})
}
67 changes: 67 additions & 0 deletions test/elasticsearch/v8.5.0/test_es_typedclient_metrics.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Copyright (c) 2024 Alibaba Group Holding Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
"context"
"log"
"os"
"strconv"
"time"

"github.com/alibaba/opentelemetry-go-auto-instrumentation/test/verifier"
"github.com/elastic/go-elasticsearch/v8"
"go.opentelemetry.io/otel/sdk/metric/metricdata"
)

var (
client *elasticsearch.TypedClient
url = "http://127.0.0.1:" + os.Getenv("OTEL_ES_PORT")
)

func main() {
var err error
client, err = elasticsearch.NewTypedClient(elasticsearch.Config{
Addresses: []string{url},
Password: "123456",
Username: "elastic",
})
if err != nil {
panic(err)
}
ctx := context.Background()
// creating an index
_, err = client.Indices.Create("my_index").Do(ctx)
if err != nil {
log.Printf("failed to create index %v\n", err)
}
time.Sleep(3 * time.Second)
port, err := strconv.Atoi(os.Getenv("OTEL_ES_PORT"))
if err != nil {
panic(err)
}
verifier.WaitAndAssertMetrics(map[string]func(metricdata.ResourceMetrics){
"http.client.request.duration": func(mrs metricdata.ResourceMetrics) {
if len(mrs.ScopeMetrics) <= 0 {
panic("No http.client.request.duration metrics received!")
}
point := mrs.ScopeMetrics[0].Metrics[0].Data.(metricdata.Histogram[float64])
if point.DataPoints[0].Count <= 0 {
panic("http.client.request.duration metrics count is not positive, actually " + strconv.Itoa(int(point.DataPoints[0].Count)))
}
verifier.VerifyHttpClientMetricsAttributes(point.DataPoints[0].Attributes.ToSlice(), "PUT", "", "", "http", "1.1", port, 200)
},
})
}
20 changes: 20 additions & 0 deletions test/elasticsearch_tests.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ const defaultTCPPort = "9300"
func init() {
TestCases = append(TestCases,
NewGeneralTestCase("es-crud-test", es_v8_module_name, "v8.4.0", "", "1.18", "", TestESCrud),
NewGeneralTestCase("es-metrics-test", es_v8_module_name, "v8.4.0", "", "1.18", "", TestESMetrics),
NewGeneralTestCase("es-typed-client-test", es_v8_module_name, "v8.4.0", "", "1.18", "", TestESTypedClient),
NewGeneralTestCase("es-typed-client-metrics-test", es_v8_module_name, "v8.5.0", "", "1.18", "", TestEsTypedClientMetrics),
NewLatestDepthTestCase("es-crud-latestdepth-test", es_v8_dependency_name, es_v8_module_name, "v8.4.0", "v8.15.0", "1.18", "", TestESCrud),
NewMuzzleTestCase("es-muzzle", es_v8_dependency_name, es_v8_module_name, "v8.4.0", "v8.4.0", "1.18", "", []string{"go", "build", "test_es_crud.go"}),
NewMuzzleTestCase("es-muzzle", es_v8_dependency_name, es_v8_module_name, "v8.5.0", "", "1.18", "", []string{"go", "build", "test_es_typedclient.go"}),
Expand All @@ -49,6 +51,15 @@ func TestESCrud(t *testing.T, env ...string) {
RunApp(t, "test_es_crud", env...)
}

func TestESMetrics(t *testing.T, env ...string) {
esC, esPort := initElasticSearchContainer()
defer testcontainers.CleanupContainer(t, esC)
UseApp("elasticsearch/v8.4.0")
RunGoBuild(t, "go", "build", "test_es_metrics.go")
env = append(env, "OTEL_ES_PORT="+esPort.Port())
RunApp(t, "test_es_metrics", env...)
}

func TestESTypedClient(t *testing.T, env ...string) {
esC, esPort := initElasticSearchContainer()
defer testcontainers.CleanupContainer(t, esC)
Expand All @@ -58,6 +69,15 @@ func TestESTypedClient(t *testing.T, env ...string) {
RunApp(t, "test_es_typedclient", env...)
}

func TestEsTypedClientMetrics(t *testing.T, env ...string) {
esC, esPort := initElasticSearchContainer()
defer testcontainers.CleanupContainer(t, esC)
UseApp("elasticsearch/v8.5.0")
RunGoBuild(t, "go", "build", "test_es_typedclient_metrics.go")
env = append(env, "OTEL_ES_PORT="+esPort.Port())
RunApp(t, "test_es_typedclient_metrics", env...)
}

func initElasticSearchContainer() (testcontainers.Container, nat.Port) {
ctx := context.Background()
elasticsearchContainer, err := runElasticSearchContainer(ctx)
Expand Down
7 changes: 7 additions & 0 deletions test/fiber_tests.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ func init() {
TestCases = append(TestCases,
NewGeneralTestCase("basic-fiberv2-test", fiberv2_module_name, "", "", "1.18", "", TestBasicFiberv2),
NewGeneralTestCase("basic-fiberv2s-test", fiberv2_module_name, "", "", "1.18", "", TestBasicFiberv2Https),
NewGeneralTestCase("basic-fiberv2-metrics-test", fiberv2_module_name, "", "", "1.18", "", TestBasicFiberv2Metrics),
NewLatestDepthTestCase("fiberv2-latestdepth", fiberv2_dependency_name, fiberv2_module_name, "v2.43.0", "", "1.18", "", TestBasicFiberv2),
NewMuzzleTestCase("fiberv2-muzzle", fiberv2_dependency_name, fiberv2_module_name, "v2.43.0", "", "1.18", "", []string{"go", "build", "fiber_http.go"}))
}
Expand All @@ -38,3 +39,9 @@ func TestBasicFiberv2Https(t *testing.T, env ...string) {
RunGoBuild(t, "go", "build", "fiber_https.go")
RunApp(t, "fiber_https", env...)
}

func TestBasicFiberv2Metrics(t *testing.T, env ...string) {
UseApp("fiberv2/v2.43.0")
RunGoBuild(t, "go", "build", "fiber_http_metrics.go")
RunApp(t, "fiber_http_metrics", env...)
}
Loading

0 comments on commit 4485e2f

Please sign in to comment.