Skip to content

Commit

Permalink
Merge pull request #118 from qonto/otel
Browse files Browse the repository at this point in the history
Add OpenTelemetry tracing
  • Loading branch information
vmercierfr authored Mar 15, 2024
2 parents 6b3ed12 + f475a1a commit e7d41d3
Show file tree
Hide file tree
Showing 18 changed files with 429 additions and 42 deletions.
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ Configuration could be defined in [prometheus-rds-exporter.yaml](https://github.
| collect-quotas | Collect AWS RDS quotas (AWS quotas API) | true |
| collect-usages | Collect AWS RDS usages (AWS Cloudwatch API) | true |
| debug | Enable debug mode | |
| enable-otel-traces | Enable OpenTelemetry traces. See [configuration](https://opentelemetry.io/docs/languages/sdk-configuration/otlp-exporter/) | false |
| listen-address | Address to listen on for web interface | :9043 |
| log-format | Log format (`text` or `json`) | json |
| metrics-path | Path under which to expose metrics | /metrics |
Expand Down Expand Up @@ -538,3 +539,23 @@ make helm-test # Helm unit test
make kubeconform # Kubernetes manifest validation
make checkcov # Check misconfigurations
```
### Tracing
Prometheus RDS Exporter includes an OpenTelemetry trace exporter to facilitate troubleshooting.
Traces can be forwarded to any OpenTelemetry server using gRPC protocol.
1. Export the `OTEL_EXPORTER_OTLP_ENDPOINT` variable.
```bash
export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317
```
See [OTEL SDK configuration](https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/#general-sdk-configuration) and [OpenTelemetry environments variables](https://opentelemetry.io/docs/languages/sdk-configuration/otlp-exporter/) for all options.
1. Start exporter with OpenTelemetry enabled
```bash
prometheus-rds-exporter --enable-otel-traces
```
16 changes: 12 additions & 4 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ type exporterConfig struct {
CollectMaintenances bool `mapstructure:"collect-maintenances"`
CollectQuotas bool `mapstructure:"collect-quotas"`
CollectUsages bool `mapstructure:"collect-usages"`
OTELTracesEnabled bool `mapstructure:"enable-otel-traces"`
}

func run(configuration exporterConfig) {
Expand Down Expand Up @@ -86,10 +87,11 @@ func run(configuration exporterConfig) {
prometheus.MustRegister(collector)

serverConfiguration := http.Config{
ListenAddress: configuration.ListenAddress,
MetricPath: configuration.MetricPath,
TLSCertPath: configuration.TLSCertPath,
TLSKeyPath: configuration.TLSKeyPath,
ListenAddress: configuration.ListenAddress,
MetricPath: configuration.MetricPath,
TLSCertPath: configuration.TLSCertPath,
TLSKeyPath: configuration.TLSKeyPath,
OTELTracesEnabled: configuration.OTELTracesEnabled,
}

server := http.New(*logger, serverConfiguration)
Expand Down Expand Up @@ -124,6 +126,7 @@ func NewRootCommand() (*cobra.Command, error) {

cmd.Flags().StringVarP(&cfgFile, "config", "c", "", "config file (default is $HOME/prometheus-rds-exporter.yaml)")
cmd.Flags().BoolP("debug", "d", false, "Enable debug mode")
cmd.Flags().BoolP("enable-otel-traces", "", false, "Enable OpenTelemetry traces")
cmd.Flags().StringP("log-format", "l", "json", "Log format (text or json)")
cmd.Flags().StringP("metrics-path", "", "/metrics", "Path under which to expose metrics")
cmd.Flags().StringP("tls-cert-path", "", "", "Path to TLS certificate")
Expand All @@ -149,6 +152,11 @@ func NewRootCommand() (*cobra.Command, error) {
return cmd, fmt.Errorf("failed to bind 'log-format' parameter: %w", err)
}

err = viper.BindPFlag("enable-otel-traces", cmd.Flags().Lookup("enable-otel-traces"))
if err != nil {
return cmd, fmt.Errorf("failed to bind 'enable-otel-traces' parameter: %w", err)
}

err = viper.BindPFlag("metrics-path", cmd.Flags().Lookup("metrics-path"))
if err != nil {
return cmd, fmt.Errorf("failed to bind 'metrics-path' parameter: %w", err)
Expand Down
4 changes: 4 additions & 0 deletions configs/prometheus-rds-exporter/prometheus-rds-exporter.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@
# Path to private key for TLS
# tls-key-path: ""

# Enable OpenTelemetry traces
# See https://opentelemetry.io/docs/languages/sdk-configuration/otlp-exporter for configuration parameters
# enable-otel-traces: true

#
# AWS credentials
#
Expand Down
20 changes: 19 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,15 @@ require (
github.com/aws/aws-sdk-go-v2/service/rds v1.75.1
github.com/aws/aws-sdk-go-v2/service/servicequotas v1.21.2
github.com/aws/aws-sdk-go-v2/service/sts v1.28.4
github.com/prometheus/client_golang v1.18.0
github.com/prometheus/client_golang v1.19.0
github.com/spf13/cobra v1.8.0
github.com/spf13/viper v1.18.2
github.com/stretchr/testify v1.9.0
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0
go.opentelemetry.io/otel v1.22.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.22.0
go.opentelemetry.io/otel/sdk v1.22.0
go.opentelemetry.io/otel/trace v1.22.0
golang.org/x/exp v0.0.0-20231127185646-65229373498e
)

Expand All @@ -29,9 +34,15 @@ require (
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.2 // indirect
github.com/aws/smithy-go v1.20.1 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/go-logr/logr v1.4.1 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
Expand All @@ -49,9 +60,16 @@ require (
github.com/spf13/cast v1.6.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.22.0 // indirect
go.opentelemetry.io/otel/metric v1.22.0 // indirect
go.opentelemetry.io/proto/otlp v1.0.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/net v0.20.0 // indirect
golang.org/x/sys v0.16.0 // indirect
golang.org/x/text v0.14.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f // indirect
google.golang.org/grpc v1.60.1 // indirect
google.golang.org/protobuf v1.33.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
Expand Down
48 changes: 48 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -34,19 +34,36 @@ github.com/aws/smithy-go v1.20.1 h1:4SZlSlMr36UEqC7XOyRVb27XMeZubNcBNN+9IgEPIQw=
github.com/aws/smithy-go v1.20.1/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo=
github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
Expand Down Expand Up @@ -105,14 +122,45 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 h1:sv9kVfal0MK0wBMCOGr+HeJm9v803BkJxGrk2au7j08=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0/go.mod h1:SK2UL73Zy1quvRPonmOmRDiWk1KBV3LyIeeIxcEApWw=
go.opentelemetry.io/otel v1.22.0 h1:xS7Ku+7yTFvDfDraDIJVpw7XPyuHlB9MCiqqX5mcJ6Y=
go.opentelemetry.io/otel v1.22.0/go.mod h1:eoV4iAi3Ea8LkAEI9+GFT44O6T/D0GWAVFyZVCC6pMI=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.22.0 h1:9M3+rhx7kZCIQQhQRYaZCdNu1V73tm4TvXs2ntl98C4=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.22.0/go.mod h1:noq80iT8rrHP1SfybmPiRGc9dc5M8RPmGvtwo7Oo7tc=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.22.0 h1:H2JFgRcGiyHg7H7bwcwaQJYrNFqCqrbTQ8K4p1OvDu8=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.22.0/go.mod h1:WfCWp1bGoYK8MeULtI15MmQVczfR+bFkk0DF3h06QmQ=
go.opentelemetry.io/otel/metric v1.22.0 h1:lypMQnGyJYeuYPhOM/bgjbFM6WE44W1/T45er4d8Hhg=
go.opentelemetry.io/otel/metric v1.22.0/go.mod h1:evJGjVpZv0mQ5QBRJoBF64yMuOf4xCWdXjK8pzFvliY=
go.opentelemetry.io/otel/sdk v1.22.0 h1:6coWHw9xw7EfClIC/+O31R8IY3/+EiRFHevmHafB2Gw=
go.opentelemetry.io/otel/sdk v1.22.0/go.mod h1:iu7luyVGYovrRpe2fmj3CVKouQNdTOkxtLzPvPz1DOc=
go.opentelemetry.io/otel/trace v1.22.0 h1:Hg6pPujv0XG9QaVbGOBVHunyuLcCC3jN7WEhPx83XD0=
go.opentelemetry.io/otel/trace v1.22.0/go.mod h1:RbbHXVqKES9QhzZq/fE5UnOSILqRt40a21sPw2He1xo=
go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I=
go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
golang.org/x/exp v0.0.0-20231127185646-65229373498e h1:Gvh4YaCaXNs6dKTlfgismwWZKyjVZXwOPfIyUaqU3No=
golang.org/x/exp v0.0.0-20231127185646-65229373498e/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 h1:wpZ8pe2x1Q3f2KyT5f8oP/fa9rHAKgFPr/HZdNuS+PQ=
google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:J7XzRzVy1+IPwWHZUzoD0IccYZIrXILAQpc+Qy9CMhY=
google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 h1:JpwMPBpFN3uKhdaekDpiNlImDdkUAyiJ6ez/uxGaUSo=
google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:0xJLfVdJqpAPl8tDg1ujOCGzx6LFLttXT5NhllGOXY4=
google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f h1:ultW7fxlIvee4HYrtnaRPon9HpEgFk5zYpmfMgtKB5I=
google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f/go.mod h1:L9KNLi232K1/xB6f7AlSX692koaRnKaWSR0stBki0Yc=
google.golang.org/grpc v1.60.1 h1:26+wFr+cNqSGFcOXcabYC0lUVJVRa2Sb2ortSK7VrEU=
google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
Expand Down
16 changes: 15 additions & 1 deletion internal/app/cloudwatch/usage.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,12 @@ import (
aws_cloudwatch "github.com/aws/aws-sdk-go-v2/service/cloudwatch"
aws_cloudwatch_types "github.com/aws/aws-sdk-go-v2/service/cloudwatch/types"
converter "github.com/qonto/prometheus-rds-exporter/internal/app/unit"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/codes"
)

var tracer = otel.Tracer("github/qonto/prometheus-rds-exporter/internal/app/cloudwatch")

type UsageMetrics struct {
AllocatedStorage float64
DBInstances float64
Expand Down Expand Up @@ -112,14 +116,16 @@ func generateCloudWatchQueriesForUsage() *aws_cloudwatch.GetMetricDataInput {
}
}

func NewUsageFetcher(client CloudWatchClient, logger slog.Logger) *usageFetcher {
func NewUsageFetcher(ctx context.Context, client CloudWatchClient, logger slog.Logger) *usageFetcher {
return &usageFetcher{
ctx: ctx,
client: client,
logger: &logger,
}
}

type usageFetcher struct {
ctx context.Context
client CloudWatchClient
statistics Statistics
logger *slog.Logger
Expand All @@ -131,6 +137,9 @@ func (u *usageFetcher) GetStatistics() Statistics {

// GetUsageMetrics returns RDS service usages metrics
func (u *usageFetcher) GetUsageMetrics() (UsageMetrics, error) {
_, span := tracer.Start(u.ctx, "collect-usage")
defer span.End()

metrics := UsageMetrics{}

query := generateCloudWatchQueriesForUsage()
Expand All @@ -152,10 +161,15 @@ func (u *usageFetcher) GetUsageMetrics() (UsageMetrics, error) {
if len(m.Values) > 0 {
err = metrics.Update(*m.Label, m.Values[0])
if err != nil {
span.SetStatus(codes.Error, "can't update internal values")
span.RecordError(err)

return metrics, fmt.Errorf("can't update internal values: %w", err)
}
}
}

span.SetStatus(codes.Ok, "metrics fetched")

return metrics, nil
}
4 changes: 3 additions & 1 deletion internal/app/cloudwatch/usage_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cloudwatch_test

import (
"context"
"log/slog"
"testing"

Expand Down Expand Up @@ -42,7 +43,8 @@ func TestGetUsageMetrics(t *testing.T) {
},
}

fetcher := cloudwatch.NewUsageFetcher(client, slog.Logger{})
ctx := context.TODO()
fetcher := cloudwatch.NewUsageFetcher(ctx, client, slog.Logger{})
result, err := fetcher.GetUsageMetrics()

require.NoError(t, err, "GetUsageMetrics must succeed")
Expand Down
22 changes: 21 additions & 1 deletion internal/app/ec2/ec2.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,18 @@ import (

aws_ec2 "github.com/aws/aws-sdk-go-v2/service/ec2"
aws_ec2_types "github.com/aws/aws-sdk-go-v2/service/ec2/types"
"github.com/qonto/prometheus-rds-exporter/internal/app/trace"
converter "github.com/qonto/prometheus-rds-exporter/internal/app/unit"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/codes"
)

const (
maxInstanceTypesPerEC2APIRequest int = 100 // Limit the number of instance types per request due to AWS API limits
)

var tracer = otel.Tracer("github/qonto/prometheus-rds-exporter/internal/app/ec2")

type EC2InstanceMetrics struct {
MaximumIops int32
MaximumThroughput float64
Expand All @@ -33,13 +38,15 @@ type EC2Client interface {
DescribeInstanceTypes(ctx context.Context, input *aws_ec2.DescribeInstanceTypesInput, fn ...func(*aws_ec2.Options)) (*aws_ec2.DescribeInstanceTypesOutput, error)
}

func NewFetcher(client EC2Client) *EC2Fetcher {
func NewFetcher(context context.Context, client EC2Client) *EC2Fetcher {
return &EC2Fetcher{
ctx: context,
client: client,
}
}

type EC2Fetcher struct {
ctx context.Context
client EC2Client
statistics Statistics
}
Expand All @@ -51,9 +58,17 @@ func (e *EC2Fetcher) GetStatistics() Statistics {
// GetDBInstanceTypeInformation returns information about specified AWS EC2 instance types
// AWS RDS API use "db." prefix while AWS EC2 API don't so we must remove it to obtains instance type information
func (e *EC2Fetcher) GetDBInstanceTypeInformation(instanceTypes []string) (Metrics, error) {
ctx, span := tracer.Start(e.ctx, "collect-ec2-metrics")
defer span.End()

metrics := make(map[string]EC2InstanceMetrics)

for _, instances := range chunkBy(instanceTypes, maxInstanceTypesPerEC2APIRequest) {
_, instanceTypeSpan := tracer.Start(ctx, "collect-ec2-instance-types-metrics")
defer instanceTypeSpan.End()

instanceTypeSpan.SetAttributes(trace.AWSInstanceTypesCount(int64(len(instances))))

// Remove "db." prefix from instance types
instanceTypesToFetch := make([]aws_ec2_types.InstanceType, len(instances))
for i, instance := range instances {
Expand All @@ -64,6 +79,9 @@ func (e *EC2Fetcher) GetDBInstanceTypeInformation(instanceTypes []string) (Metri

resp, err := e.client.DescribeInstanceTypes(context.TODO(), input)
if err != nil {
instanceTypeSpan.SetStatus(codes.Error, "can't fetch describe instance types")
instanceTypeSpan.RecordError(err)

return Metrics{}, fmt.Errorf("can't fetch describe instance types: %w", err)
}

Expand All @@ -78,6 +96,8 @@ func (e *EC2Fetcher) GetDBInstanceTypeInformation(instanceTypes []string) (Metri
Memory: converter.MegaBytesToBytes(*i.MemoryInfo.SizeInMiB),
}
}

instanceTypeSpan.SetStatus(codes.Ok, "metrics fetched")
}

return Metrics{
Expand Down
4 changes: 3 additions & 1 deletion internal/app/ec2/ec2_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package ec2_test

import (
"context"
"testing"

"github.com/qonto/prometheus-rds-exporter/internal/app/ec2"
Expand All @@ -11,10 +12,11 @@ import (
)

func TestGetDBInstanceTypeInformation(t *testing.T) {
context := context.TODO()
client := mock.EC2Client{}

instanceTypes := []string{"db.t3.large", "db.t3.small"}
fetcher := ec2.NewFetcher(client)
fetcher := ec2.NewFetcher(context, client)
result, err := fetcher.GetDBInstanceTypeInformation(instanceTypes)

require.NoError(t, err, "GetDBInstanceTypeInformation must succeed")
Expand Down
Loading

0 comments on commit e7d41d3

Please sign in to comment.