forked from open-telemetry/opentelemetry-collector-contrib
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* slow sql connector Signed-off-by: Jared Tan <jian.tan@daocloud.io> * slow sql connector Signed-off-by: Jared Tan <jian.tan@daocloud.io> * update builder-config.yaml Signed-off-by: Jared Tan <jian.tan@daocloud.io> * update db sysystem filter Signed-off-by: Jared Tan <jian.tan@daocloud.io> * update span name Signed-off-by: Jared Tan <jian.tan@daocloud.io> --------- Signed-off-by: Jared Tan <jian.tan@daocloud.io>
- Loading branch information
1 parent
66756a8
commit eb233ab
Showing
26 changed files
with
1,152 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
include ../../Makefile.Common |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
// Copyright The OpenTelemetry Authors | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package slowsqlconnector // import "github.com/open-telemetry/opentelemetry-collector-contrib/connector/slowsqlconnector" | ||
|
||
import ( | ||
"fmt" | ||
|
||
"go.opentelemetry.io/collector/component" | ||
) | ||
|
||
// Dimension defines the dimension name and optional default value if the Dimension is missing from a span attribute. | ||
type Dimension struct { | ||
Name string `mapstructure:"name"` | ||
Default *string `mapstructure:"default"` | ||
} | ||
|
||
type Exemplars struct { | ||
Enabled bool `mapstructure:"enabled"` | ||
} | ||
|
||
// Config defines the configuration options for exceptionsconnector | ||
type Config struct { | ||
// Threshold of slow sql. unit is seconds, default 1s. | ||
Threshold float64 `mapstructure:"threshold"` | ||
// Filter specific db systems, default "h2", "mongodb", "mssql", "mysql", "oracle", "progress", "postgresql", "mariadb", ref: https://opentelemetry.io/docs/specs/semconv/attributes-registry/db/ | ||
DBSystem []string `mapstructure:"db_system"` | ||
// Dimensions defines the list of additional dimensions on top of the provided: | ||
// - service.name | ||
// - span.name | ||
// - span.kind | ||
// - status.code | ||
// The dimensions will be fetched from the span's attributes. Examples of some conventionally used attributes: | ||
// https://github.com/open-telemetry/opentelemetry-collector/blob/main/model/semconv/opentelemetry.go. | ||
Dimensions []Dimension `mapstructure:"dimensions"` | ||
// Exemplars defines the configuration for exemplars. | ||
Exemplars Exemplars `mapstructure:"exemplars"` | ||
} | ||
|
||
var _ component.ConfigValidator = (*Config)(nil) | ||
|
||
// Validate checks if the connector configuration is valid | ||
func (c Config) Validate() error { | ||
err := validateDimensions(c.Dimensions) | ||
if err != nil { | ||
return err | ||
} | ||
return nil | ||
} | ||
|
||
// validateDimensions checks duplicates for reserved dimensions and additional dimensions. | ||
func validateDimensions(dimensions []Dimension) error { | ||
labelNames := make(map[string]struct{}) | ||
for _, key := range []string{serviceNameKey, spanKindKey, spanNameKey, statusCodeKey} { | ||
labelNames[key] = struct{}{} | ||
} | ||
|
||
for _, key := range dimensions { | ||
if _, ok := labelNames[key.Name]; ok { | ||
return fmt.Errorf("duplicate dimension name %q", key.Name) | ||
} | ||
labelNames[key.Name] = struct{}{} | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
// Copyright The OpenTelemetry Authors | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package slowsqlconnector | ||
|
||
import ( | ||
"path/filepath" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
"go.opentelemetry.io/collector/component" | ||
"go.opentelemetry.io/collector/confmap/confmaptest" | ||
|
||
"github.com/open-telemetry/opentelemetry-collector-contrib/connector/slowsqlconnector/internal/metadata" | ||
) | ||
|
||
func TestLoadConfig(t *testing.T) { | ||
t.Parallel() | ||
|
||
cm, err := confmaptest.LoadConf(filepath.Join("testdata", "config.yaml")) | ||
require.NoError(t, err) | ||
|
||
tests := []struct { | ||
id component.ID | ||
expected component.Config | ||
}{ | ||
{ | ||
id: component.NewIDWithName(metadata.Type, "default"), | ||
expected: createDefaultConfig(), | ||
}, | ||
{ | ||
id: component.NewIDWithName(metadata.Type, "full"), | ||
expected: &Config{ | ||
Threshold: 1, | ||
Dimensions: []Dimension{ | ||
{Name: "k8s.uuid"}, | ||
{Name: "k8s.namespace.name"}, | ||
}, | ||
Exemplars: Exemplars{ | ||
Enabled: false, | ||
}, | ||
}, | ||
}, | ||
} | ||
|
||
for _, tt := range tests { | ||
t.Run(tt.id.String(), func(t *testing.T) { | ||
factory := NewFactory() | ||
cfg := factory.CreateDefaultConfig() | ||
|
||
sub, err := cm.Sub(tt.id.String()) | ||
require.NoError(t, err) | ||
err = sub.Unmarshal(cfg) | ||
assert.NoError(t, err) | ||
assert.NoError(t, component.ValidateConfig(cfg)) | ||
assert.Equal(t, tt.expected, cfg) | ||
}) | ||
} | ||
} | ||
|
||
func TestValidateDimensions(t *testing.T) { | ||
for _, tc := range []struct { | ||
name string | ||
dimensions []Dimension | ||
expectedErr string | ||
}{ | ||
{ | ||
name: "no additional dimensions", | ||
dimensions: []Dimension{}, | ||
}, | ||
{ | ||
name: "no duplicate dimensions", | ||
dimensions: []Dimension{ | ||
{Name: "http.service_name"}, | ||
{Name: "http.status_code"}, | ||
}, | ||
}, | ||
{ | ||
name: "duplicate dimension with reserved labels", | ||
dimensions: []Dimension{ | ||
{Name: "service.name"}, | ||
}, | ||
expectedErr: "duplicate dimension name \"service.name\"", | ||
}, | ||
{ | ||
name: "duplicate additional dimensions", | ||
dimensions: []Dimension{ | ||
{Name: "service_name"}, | ||
{Name: "service_name"}, | ||
}, | ||
expectedErr: "duplicate dimension name \"service_name\"", | ||
}, | ||
} { | ||
t.Run(tc.name, func(t *testing.T) { | ||
err := validateDimensions(tc.dimensions) | ||
if tc.expectedErr != "" { | ||
assert.EqualError(t, err, tc.expectedErr) | ||
} else { | ||
assert.NoError(t, err) | ||
} | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
// Copyright The OpenTelemetry Authors | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package slowsqlconnector // import "github.com/open-telemetry/opentelemetry-collector-contrib/connector/slowsqlconnector" | ||
|
||
import ( | ||
"go.opentelemetry.io/collector/pdata/pcommon" | ||
conventions "go.opentelemetry.io/collector/semconv/v1.18.0" | ||
) | ||
|
||
const ( | ||
serviceNameKey = conventions.AttributeServiceName | ||
spanKindKey = "span.kind" // OpenTelemetry non-standard constant. | ||
spanNameKey = "span.name" // OpenTelemetry non-standard constant. | ||
statusCodeKey = "status.code" // OpenTelemetry non-standard constant. | ||
dbStatementKey = conventions.AttributeDBStatement // OpenTelemetry non-standard constant. | ||
dbSystemKey = conventions.AttributeDBSystem // OpenTelemetry non-standard constant. | ||
statementExecDuration = "db.statement.duration" // OpenTelemetry non-standard constant. | ||
) | ||
|
||
type dimension struct { | ||
name string | ||
value *pcommon.Value | ||
} | ||
|
||
func newDimensions(cfgDims []Dimension) []dimension { | ||
if len(cfgDims) == 0 { | ||
return nil | ||
} | ||
dims := make([]dimension, len(cfgDims)) | ||
for i := range cfgDims { | ||
dims[i].name = cfgDims[i].Name | ||
if cfgDims[i].Default != nil { | ||
val := pcommon.NewValueStr(*cfgDims[i].Default) | ||
dims[i].value = &val | ||
} | ||
} | ||
return dims | ||
} | ||
|
||
// getDimensionValue gets the dimension value for the given configured dimension. | ||
// It searches through the span's attributes first, being the more specific; | ||
// falling back to searching in resource attributes if it can't be found in the span. | ||
// Finally, falls back to the configured default value if provided. | ||
// | ||
// The ok flag indicates if a dimension value was fetched in order to differentiate | ||
// an empty string value from a state where no value was found. | ||
func getDimensionValue(d dimension, spanAttrs pcommon.Map, resourceAttr pcommon.Map) (v pcommon.Value, ok bool) { | ||
// The more specific span attribute should take precedence. | ||
if attr, exists := spanAttrs.Get(d.name); exists { | ||
return attr, true | ||
} | ||
// falling back to searching in resource attributes | ||
if attr, exists := resourceAttr.Get(d.name); exists { | ||
return attr, true | ||
} | ||
// Set the default if configured, otherwise this metric will have no value set for the dimension. | ||
if d.value != nil { | ||
return *d.value, true | ||
} | ||
return v, ok | ||
} | ||
|
||
func findAttributeValue(key string, attributes ...pcommon.Map) (string, bool) { | ||
for _, attr := range attributes { | ||
if v, ok := attr.Get(key); ok { | ||
return v.AsString(), true | ||
} | ||
} | ||
return "", false | ||
} |
Oops, something went wrong.