Skip to content

Commit

Permalink
added profiling stats and query stats
Browse files Browse the repository at this point in the history
  • Loading branch information
arjun-mw committed Oct 4, 2024
1 parent 9a4209d commit 3c3a6b7
Show file tree
Hide file tree
Showing 15 changed files with 1,343 additions and 23 deletions.
87 changes: 87 additions & 0 deletions receiver/mongodbreceiver/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"go.uber.org/zap"
"golang.org/x/exp/slices"
)

// client is an interface that exposes functionality towards a mongo environment
Expand All @@ -34,6 +35,8 @@ type client interface {
JumboStats(ctx context.Context, DBName string) (bson.M, error)
CollectionStats(ctx context.Context, DBName, collectionName string) (bson.M, error)
ConnPoolStats(ctx context.Context, DBName string) (bson.M, error)
ProfilingStats(ctx context.Context, DBName string) (bson.M, error)
QueryStats(ctx context.Context, DBName string) ([]SlowOperationEvent, error)
}

// mongodbClient is a mongodb metric scraper client
Expand Down Expand Up @@ -397,3 +400,87 @@ func (c *mongodbClient) GetFsyncLockInfo(ctx context.Context) (bson.M, error) {

return fsynclockinfo, nil
}

type ProfilingStatus struct {
Level int32 `bson:"level"`
Slow int32 `bson:"slowms"`
}

// ProfilingStats returns the result of db.runCommand({"profile":-1}) or db.getProfilingStatus()
// more information can be found here: https://www.mongodb.com/docs/manual/tutorial/manage-the-database-profiler/
func (c *mongodbClient) ProfilingStats(ctx context.Context, database string) (bson.M, error) {
excluded_dbs := []string{"local", "admin", "config", "test"}

if !slices.Contains(excluded_dbs, database) {

cfgLevel := c.cfg.ProfilingLevel
cfgSlowms := c.cfg.SlowMs
var result bson.M

db := c.Database(database)
err := db.RunCommand(ctx, bson.D{{"profile", -1}}).Decode(&result)
if err != nil {
return nil, fmt.Errorf("unable to get profiling stats: %w", err)
}

level := (result["was"].(int32))
slowms := (result["slowms"].(int32))

if ((level != cfgLevel) && slices.Contains([]int32{0, 1, 2}, cfgLevel)) || (slowms != cfgSlowms) {
command := bson.D{
{"profile", cfgLevel},
{"slowms", cfgSlowms},
}
var profile bson.M
err = db.RunCommand(ctx, command).Decode(&profile)
if err != nil {
return nil, fmt.Errorf("unable to set for database:%s profiling: %w", database, err)
}

result = bson.M{
"level": profile["was"],
"slowms": profile["slowms"],
}
return result, nil
} else {
result = bson.M{
"level": level,
"slowms": slowms,
}
return result, nil
}

}

return nil, fmt.Errorf("this is excluded database:%s for stats", database)
}

// QueryStats returns the result of find on system.profile or db.getProfilingStatus()
// more information can be found here: https://www.mongodb.com/docs/manual/tutorial/manage-the-database-profiler/
func (c *mongodbClient) QueryStats(ctx context.Context, database string) ([]SlowOperationEvent, error) {
excluded_dbs := []string{"local", "admin", "config", "test"}

if !slices.Contains(excluded_dbs, database) {
var result bson.M

db := c.Database(database)
err := db.RunCommand(ctx, bson.D{{"profile", -1}}).Decode(&result)
if err != nil {
return nil, fmt.Errorf("unable to get profiling stats: %w", err)
}

level := (result["was"].(int32))

if slices.Contains([]int32{1, 2}, level) {
lastTs := time.Now().Add(-c.cfg.CollectionInterval - time.Second)
events, err := collectSlowOperations(ctx, c.Client, database, lastTs)
if err != nil {
return nil, fmt.Errorf("unable to get query stats: %w", err)
}
return events, nil
}

}

return nil, fmt.Errorf("unable to get other database for stats")
}
8 changes: 8 additions & 0 deletions receiver/mongodbreceiver/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,14 @@ func (fc *fakeClient) ConnPoolStats(ctx context.Context, dbName string) (bson.M,
args := fc.Called(ctx, dbName)
return args.Get(0).(bson.M), args.Error(1)
}
func (fc *fakeClient) ProfilingStats(ctx context.Context, dbName string) (bson.M, error) {
args := fc.Called(ctx, dbName)
return args.Get(0).(bson.M), args.Error(1)
}
func (fc *fakeClient) QueryStats(ctx context.Context, dbName string) ([]SlowOperationEvent, error) {
args := fc.Called(ctx, dbName)
return args.Get(0).([]SlowOperationEvent), args.Error(1)
}

func TestListDatabaseNames(t *testing.T) {
mont := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
Expand Down
18 changes: 10 additions & 8 deletions receiver/mongodbreceiver/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,13 @@ type Config struct {
// MetricsBuilderConfig defines which metrics/attributes to enable for the scraper
metadata.MetricsBuilderConfig `mapstructure:",squash"`
// Deprecated - Transport option will be removed in v0.102.0
Hosts []confignet.TCPAddrConfig `mapstructure:"hosts"`
Username string `mapstructure:"username"`
Password configopaque.String `mapstructure:"password"`
ReplicaSet string `mapstructure:"replica_set,omitempty"`
Timeout time.Duration `mapstructure:"timeout"`
Hosts []confignet.TCPAddrConfig `mapstructure:"hosts"`
Username string `mapstructure:"username"`
Password configopaque.String `mapstructure:"password"`
ReplicaSet string `mapstructure:"replica_set,omitempty"`
Timeout time.Duration `mapstructure:"timeout"`
ProfilingLevel int32 `mapstructure:"profiling_level"`
SlowMs int32 `mapstructure:"slow_ms"`
}

func (c *Config) Validate() error {
Expand Down Expand Up @@ -79,9 +81,9 @@ func (c *Config) ClientOptions() *options.ClientOptions {
if c.Username != "" && c.Password != "" {
clientOptions.SetAuth(options.Credential{
AuthMechanism: "SCRAM-SHA-1",
Username: c.Username,
Password: string(c.Password),
AuthSource: "admin",
Username: c.Username,
Password: string(c.Password),
AuthSource: "admin",
})
}

Expand Down
81 changes: 81 additions & 0 deletions receiver/mongodbreceiver/documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -2912,6 +2912,34 @@ Total amount of space used by the oplog.
| ---- | ----------- | ------ |
| database | The name of a database. | Any Str |

### mongodb.profiling.level

Specifies which operations should be profiled.

| Unit | Metric Type | Value Type |
| ---- | ----------- | ---------- |
| 1 | Gauge | Int |

#### Attributes

| Name | Description | Values |
| ---- | ----------- | ------ |
| database | The name of a database. | Any Str |

### mongodb.profiling.slowms

Specifies which operations should be profiled based on slowms in milliseconds. Works only for profile level '1',

| Unit | Metric Type | Value Type |
| ---- | ----------- | ---------- |
| ms | Gauge | Int |

#### Attributes

| Name | Description | Values |
| ---- | ----------- | ------ |
| database | The name of a database. | Any Str |

### mongodb.replset.health

Member health value of the replica set: conveys if the member is up (i.e. 1) or down (i.e. 0).
Expand Down Expand Up @@ -3024,6 +3052,59 @@ The total number of active sessions.
| ---- | ----------- | ---------- | ----------------------- | --------- |
| {sessions} | Sum | Int | Cumulative | false |

### mongodb.slow_operation.time

The total time spent performing operations with slowms. Works only for profile level '1' & '2',

| Unit | Metric Type | Value Type |
| ---- | ----------- | ---------- |
| ms | Gauge | Int |

#### Attributes

| Name | Description | Values |
| ---- | ----------- | ------ |
| timestamp | The time when the slow operation occurred. | Any Int |
| database | The name of a database. | Any Str |
| operation | The MongoDB operation being counted. | Str: ``insert``, ``query``, ``update``, ``delete``, ``getmore``, ``command`` |
| ns | The namespace of the operation (typically "database.collection"). | Any Str |
| plan_summary | A summary of the execution plan used for the query. | Any Str |
| query_signature | A signature that uniquely identifies the query for performance analysis. | Any Str |
| user | The user who executed the operation (only available with profiling). | Any Str |
| application | The application name that executed the operation (only available with profiling). | Any Str |
| statement | The actual command or query that was executed. | Any Str |
| raw_query | The raw representation of the query as it was sent to MongoDB. | Any Str |
| query_hash | A hash that uniquely identifies the query (only available with profiling). | Any Str |
| query_shape_hash | A hash representing the shape of the query. | Any Str |
| plan_cache_key | A key used to identify the execution plan in the cache (only available with profiling). | Any Str |
| query_framework | The framework used for executing the query. | Any Str |
| comment | Any comments associated with the command. | Any Str |
| mills | Duration of the operation in milliseconds. | Any Int |
| num_yields | Number of times the operation yielded control (for long-running operations). | Any Int |
| response_length | Length of the response returned by the operation. | Any Int |
| nreturned | Number of documents returned by the query. | Any Int |
| nmatched | Number of documents matched by the query. | Any Int |
| nmodified | Number of documents modified by the operation. | Any Int |
| ninserted | Number of documents inserted by the operation. | Any Int |
| ndeleted | Number of documents deleted by the operation. | Any Int |
| keys_examined | Number of index keys examined during execution. | Any Int |
| docs_examined | Number of documents examined during execution. | Any Int |
| keys_inserted | Number of index keys inserted during execution. | Any Int |
| write_conflicts | Number of write conflicts encountered during execution. | Any Int |
| cpu_nanos | CPU time consumed by the operation in nanoseconds. | Any Int |
| planning_time_micros | Time taken to plan the query in microseconds (only available with profiling). | Any Int |
| cursor_exhausted | Indicates whether the cursor was exhausted during execution. | Any Bool |
| upsert | Indicates if an upsert operation was performed (only available with profiling). | Any Bool |
| has_sort_stage | Indicates if a sort stage was present in the operation (only available with profiling). | Any Bool |
| used_disk | Disk usage information related to this operation (only available with profiling). | Any Str |
| from_multi_planner | Indicates if this operation came from a multi-planner (only available with profiling). | Any Str |
| replanned | Indicates if this operation was replanned (only available with profiling). | Any Str |
| replan_reason | Reason for replanning this operation (only available with profiling). | Any Str |
| client | Information about the client that executed this operation (only available with profiling). | Any Str |
| cursor | Cursor details related to this operation (only available with profiling). | Any Str |
| lock_stats | Lock statistics related to this operation (only available with profiling). | Any Str |
| flow_control_stats | Flow control statistics related to this operation (only available with profiling). | Any Str |

### mongodb.stats.avgobjsize

The average size of each document in bytes.
Expand Down
33 changes: 18 additions & 15 deletions receiver/mongodbreceiver/go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
module github.com/open-telemetry/opentelemetry-collector-contrib/receiver/mongodbreceiver

go 1.21.0
go 1.22.0

toolchain go1.22.2

require (
github.com/google/go-cmp v0.6.0
Expand All @@ -10,7 +12,7 @@ require (
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest v0.102.0
github.com/stretchr/testify v1.9.0
github.com/testcontainers/testcontainers-go v0.31.0
go.mongodb.org/mongo-driver v1.15.0
go.mongodb.org/mongo-driver v1.17.0
go.opentelemetry.io/collector/component v0.102.2-0.20240606174409-6888f8f7a45f
go.opentelemetry.io/collector/config/confignet v0.102.2-0.20240606174409-6888f8f7a45f
go.opentelemetry.io/collector/config/configopaque v1.9.1-0.20240606174409-6888f8f7a45f
Expand All @@ -19,7 +21,7 @@ require (
go.opentelemetry.io/collector/consumer v0.102.2-0.20240606174409-6888f8f7a45f
go.opentelemetry.io/collector/featuregate v1.9.1-0.20240606174409-6888f8f7a45f
go.opentelemetry.io/collector/filter v0.102.2-0.20240606174409-6888f8f7a45f
go.opentelemetry.io/collector/pdata v1.9.1-0.20240606174409-6888f8f7a45f
go.opentelemetry.io/collector/pdata v1.16.0
go.opentelemetry.io/collector/receiver v0.102.2-0.20240606174409-6888f8f7a45f
go.opentelemetry.io/otel/metric v1.27.0
go.opentelemetry.io/otel/trace v1.27.0
Expand Down Expand Up @@ -68,7 +70,7 @@ require (
github.com/moby/term v0.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect
github.com/montanaflynn/stats v0.7.1 // indirect
github.com/morikuni/aec v1.0.0 // indirect
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatautil v0.102.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
Expand All @@ -89,7 +91,7 @@ require (
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
github.com/xdg-go/scram v1.1.2 // indirect
github.com/xdg-go/stringprep v1.0.4 // indirect
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect
go.opentelemetry.io/collector v0.102.2-0.20240606174409-6888f8f7a45f // indirect
go.opentelemetry.io/collector/config/configtelemetry v0.102.2-0.20240606174409-6888f8f7a45f // indirect
Expand All @@ -98,16 +100,17 @@ require (
go.opentelemetry.io/otel/exporters/prometheus v0.49.0 // indirect
go.opentelemetry.io/otel/sdk v1.27.0 // indirect
go.opentelemetry.io/otel/sdk/metric v1.27.0 // indirect
golang.org/x/crypto v0.23.0 // indirect
golang.org/x/mod v0.17.0 // indirect
golang.org/x/net v0.25.0 // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/sys v0.20.0 // indirect
golang.org/x/text v0.16.0 // indirect
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240520151616-dc85e6b867a5 // indirect
google.golang.org/grpc v1.64.0 // indirect
google.golang.org/protobuf v1.34.1 // indirect
golang.org/x/crypto v0.27.0 // indirect
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect
golang.org/x/mod v0.21.0 // indirect
golang.org/x/net v0.29.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.25.0 // indirect
golang.org/x/text v0.18.0 // indirect
golang.org/x/tools v0.25.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 // indirect
google.golang.org/grpc v1.66.2 // indirect
google.golang.org/protobuf v1.34.2 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

Expand Down
Loading

0 comments on commit 3c3a6b7

Please sign in to comment.