Skip to content

[mongodbatlasreceiver] Add baseURL config #39345

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
9549eb2
add baseURL config
ArturSantosTD Apr 11, 2025
09852da
change atlas client
ArturSantosTD Apr 11, 2025
2da8fc6
Merge branch 'main' of https://github.com/ArturSantosTD/opentelemetry…
ArturSantosTD Apr 11, 2025
c17529d
update docs
ArturSantosTD Apr 11, 2025
34b591c
run make generate
ArturSantosTD Apr 11, 2025
14c9432
Merge branch 'main' into feat--Add-support-for-atlasgov
ArturSantosTD Apr 11, 2025
edb48e4
make chlog-new
ArturSantosTD Apr 11, 2025
89668a0
fix tests
ArturSantosTD Apr 11, 2025
221821d
requested changes
ArturSantosTD Apr 14, 2025
9913a78
error handling when calling mongodbatlas.New
ArturSantosTD Apr 14, 2025
e07b6c9
Merge branch 'main' into feat--Add-support-for-atlasgov
ArturSantosTD Apr 15, 2025
38d562b
go fmt
ArturSantosTD Apr 15, 2025
6799980
Merge branch 'main' of https://github.com/ArturSantosTD/opentelemetry…
ArturSantosTD Apr 18, 2025
9971e57
suggested changes
ArturSantosTD Apr 18, 2025
ed8b145
update url validation
ArturSantosTD Apr 18, 2025
065b73a
go lint
ArturSantosTD Apr 18, 2025
e76e494
fix config tests
ArturSantosTD Apr 18, 2025
b262dd2
fix tests
ArturSantosTD Apr 18, 2025
440ebe4
make generate
ArturSantosTD Apr 22, 2025
3c60e37
updat tests
ArturSantosTD Apr 22, 2025
4879c57
Merge branch 'main' into feat--Add-support-for-atlasgov
ChrsMark Apr 30, 2025
92e480a
Merge branch 'main' into feat--Add-support-for-atlasgov
ArturSantosTD May 1, 2025
9f5d0fd
Merge branch 'main' into feat--Add-support-for-atlasgov
edmocosta May 5, 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
27 changes: 27 additions & 0 deletions .chloggen/feat--Add-support-for-atlasgov.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Use this changelog template to create an entry for release notes.

# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
change_type: enhancement

# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
component: mongodbatlasreceiver

# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
note: "Add support for setting custom base URL for the MongoDB Atlas API"

# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
issues: [39345]

# (Optional) One or more lines of additional information to render under the primary note.
# These lines will be padded with 2 spaces and then inserted directly into the document.
# Use pipe (|) for multiline entries.
subtext:

# If your change doesn't affect end users or the exported elements of any package,
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.
# Optional: The change log or logs in which this entry should be included.
# e.g. '[user]' or '[user, api]'
# Include 'user' if the change is relevant to end users.
# Include 'api' if there is a change to a library API.
# Default: '[user]'
change_logs: [user]
1 change: 1 addition & 0 deletions receiver/mongodbatlasreceiver/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ In order to collect access logs, the requesting API key needs the appropriate pe

MongoDB Atlas [Documentation](https://www.mongodb.com/docs/atlas/reference/api/logs/#logs) recommends a polling interval of 5 minutes.

- `base_url` (optional) set the base URL to connect to to Atlas Cloud
- `public_key` (required for metrics, logs, or alerts in `poll` mode)
- `private_key` (required for metrics, logs, or alerts in `poll` mode)
- `granularity` (default `PT1M` - See [MongoDB Atlas Documentation](https://docs.atlas.mongodb.com/reference/api/process-measurements/))
Expand Down
11 changes: 8 additions & 3 deletions receiver/mongodbatlasreceiver/access_logs.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,15 @@ type accessLogsReceiver struct {
cancel context.CancelFunc
}

func newAccessLogsReceiver(settings rcvr.Settings, cfg *Config, consumer consumer.Logs) *accessLogsReceiver {
func newAccessLogsReceiver(settings rcvr.Settings, cfg *Config, consumer consumer.Logs) (*accessLogsReceiver, error) {
client, err := internal.NewMongoDBAtlasClient(cfg.BaseURL, cfg.PublicKey, string(cfg.PrivateKey), cfg.BackOffConfig, settings.Logger)
if err != nil {
return nil, fmt.Errorf("failed to create MongoDB Atlas client for access logs receiver: %w", err)
}

r := &accessLogsReceiver{
cancel: func() {},
client: internal.NewMongoDBAtlasClient(cfg.PublicKey, string(cfg.PrivateKey), cfg.BackOffConfig, settings.Logger),
client: client,
cfg: cfg,
logger: settings.Logger,
consumer: consumer,
Expand All @@ -80,7 +85,7 @@ func newAccessLogsReceiver(settings rcvr.Settings, cfg *Config, consumer consume
}
}

return r
return r, nil
}

func (alr *accessLogsReceiver) Start(ctx context.Context, _ component.Host, storageClient storage.Client) error {
Expand Down
10 changes: 8 additions & 2 deletions receiver/mongodbatlasreceiver/access_logs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,10 @@ func TestAccessLogsRetrieval(t *testing.T) {
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
logSink := &consumertest.LogsSink{}
rcvr := newAccessLogsReceiver(receivertest.NewNopSettings(metadata.Type), tc.config(), logSink)
rcvr, e := newAccessLogsReceiver(receivertest.NewNopSettings(metadata.Type), tc.config(), logSink)
if e != nil {
t.Fatalf("failed to create receiver: %v", e)
}
tc.setup(rcvr)

err := rcvr.Start(context.Background(), componenttest.NewNopHost(), storage.NewNopClient())
Expand Down Expand Up @@ -314,7 +317,10 @@ func TestCheckpointing(t *testing.T) {
}

logSink := &consumertest.LogsSink{}
rcvr := newAccessLogsReceiver(receivertest.NewNopSettings(metadata.Type), config, logSink)
rcvr, e := newAccessLogsReceiver(receivertest.NewNopSettings(metadata.Type), config, logSink)
if e != nil {
t.Fatalf("failed to create receiver: %v", e)
}
rcvr.client = simpleAccessLogClient()

// First cluster checkpoint should be nil
Expand Down
9 changes: 8 additions & 1 deletion receiver/mongodbatlasreceiver/alerts.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ type alertsReceiver struct {
// only relevant in `poll` mode
projects []*ProjectConfig
client alertsClient
baseURL string
privateKey string
publicKey string
backoffConfig configretry.BackOffConfig
Expand Down Expand Up @@ -108,6 +109,7 @@ func newAlertsReceiver(params rcvr.Settings, baseConfig *Config, consumer consum
mode: cfg.Mode,
projects: cfg.Projects,
backoffConfig: baseConfig.BackOffConfig,
baseURL: baseConfig.BaseURL,
publicKey: baseConfig.PublicKey,
privateKey: string(baseConfig.PrivateKey),
wg: &sync.WaitGroup{},
Expand All @@ -119,7 +121,12 @@ func newAlertsReceiver(params rcvr.Settings, baseConfig *Config, consumer consum
}

if recv.mode == alertModePoll {
recv.client = internal.NewMongoDBAtlasClient(recv.publicKey, recv.privateKey, recv.backoffConfig, recv.telemetrySettings.Logger)
client, err := internal.NewMongoDBAtlasClient(recv.baseURL, recv.publicKey, recv.privateKey, recv.backoffConfig, recv.telemetrySettings.Logger)
if err != nil {
return nil, fmt.Errorf("failed to create MongoDB Atlas client for alerts receiver: %w", err)
}

recv.client = client
return recv, nil
}
s := &http.Server{
Expand Down
1 change: 1 addition & 0 deletions receiver/mongodbatlasreceiver/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ var _ component.Config = (*Config)(nil)

type Config struct {
scraperhelper.ControllerConfig `mapstructure:",squash"`
BaseURL string `mapstructure:"base_url"`
PublicKey string `mapstructure:"public_key"`
PrivateKey configopaque.String `mapstructure:"private_key"`
Granularity string `mapstructure:"granularity"`
Expand Down
11 changes: 8 additions & 3 deletions receiver/mongodbatlasreceiver/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,14 @@ type eventRecord struct {
NextStartTime *time.Time `mapstructure:"next_start_time"`
}

func newEventsReceiver(settings rcvr.Settings, c *Config, consumer consumer.Logs) *eventsReceiver {
func newEventsReceiver(settings rcvr.Settings, c *Config, consumer consumer.Logs) (*eventsReceiver, error) {
client, err := internal.NewMongoDBAtlasClient(c.BaseURL, c.PublicKey, string(c.PrivateKey), c.BackOffConfig, settings.Logger)
if err != nil {
return nil, fmt.Errorf("failed to create MongoDB Atlas client for events receiver: %w", err)
}

r := &eventsReceiver{
client: internal.NewMongoDBAtlasClient(c.PublicKey, string(c.PrivateKey), c.BackOffConfig, settings.Logger),
client: client,
cfg: c,
logger: settings.Logger,
consumer: consumer,
Expand All @@ -82,7 +87,7 @@ func newEventsReceiver(settings rcvr.Settings, c *Config, consumer consumer.Logs
r.pollInterval = time.Minute
}

return r
return r, nil
}

func (er *eventsReceiver) Start(ctx context.Context, _ component.Host, storageClient storage.Client) error {
Expand Down
20 changes: 16 additions & 4 deletions receiver/mongodbatlasreceiver/events_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,10 @@ func TestStartAndShutdown(t *testing.T) {
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
sink := &consumertest.LogsSink{}
r := newEventsReceiver(receivertest.NewNopSettings(metadata.Type), tc.getConfig(), sink)
r, e := newEventsReceiver(receivertest.NewNopSettings(metadata.Type), tc.getConfig(), sink)
if e != nil {
t.Fatalf("failed to create receiver: %v", e)
}
err := r.Start(context.Background(), componenttest.NewNopHost(), storage.NewNopClient())
if tc.expectedStartErr != nil {
require.ErrorContains(t, err, tc.expectedStartErr.Error())
Expand All @@ -80,7 +83,10 @@ func TestContextDone(t *testing.T) {
},
}
sink := &consumertest.LogsSink{}
r := newEventsReceiver(receivertest.NewNopSettings(metadata.Type), cfg, sink)
r, er := newEventsReceiver(receivertest.NewNopSettings(metadata.Type), cfg, sink)
if er != nil {
t.Fatalf("failed to create receiver: %v", er)
}
r.pollInterval = 500 * time.Millisecond
mClient := &mockEventsClient{}
mClient.setupMock(t)
Expand Down Expand Up @@ -116,7 +122,10 @@ func TestPoll(t *testing.T) {
}

sink := &consumertest.LogsSink{}
r := newEventsReceiver(receivertest.NewNopSettings(metadata.Type), cfg, sink)
r, e := newEventsReceiver(receivertest.NewNopSettings(metadata.Type), cfg, sink)
if e != nil {
t.Fatalf("failed to create receiver: %v", e)
}
mClient := &mockEventsClient{}
mClient.setupMock(t)
r.client = mClient
Expand Down Expand Up @@ -161,7 +170,10 @@ func TestProjectGetFailure(t *testing.T) {
}

sink := &consumertest.LogsSink{}
r := newEventsReceiver(receivertest.NewNopSettings(metadata.Type), cfg, sink)
r, e := newEventsReceiver(receivertest.NewNopSettings(metadata.Type), cfg, sink)
if e != nil {
t.Fatalf("failed to create receiver: %v", e)
}
mClient := &mockEventsClient{}
mClient.On("GetProject", mock.Anything, "fake-project").Return(nil, fmt.Errorf("unable to get project: %d", http.StatusUnauthorized))
mClient.On("GetOrganization", mock.Anything, "fake-org").Return(nil, fmt.Errorf("unable to get org: %d", http.StatusUnauthorized))
Expand Down
20 changes: 16 additions & 4 deletions receiver/mongodbatlasreceiver/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,10 @@ func createMetricsReceiver(
consumer consumer.Metrics,
) (receiver.Metrics, error) {
cfg := rConf.(*Config)
recv := newMongoDBAtlasReceiver(params, cfg)
recv, err := newMongoDBAtlasReceiver(params, cfg)
if err != nil {
return nil, fmt.Errorf("unable to create a MongoDB Atlas Receiver instance: %w", err)
}
ms, err := newMongoDBAtlasScraper(recv)
if err != nil {
return nil, fmt.Errorf("unable to create a MongoDB Atlas Scraper instance: %w", err)
Expand Down Expand Up @@ -75,18 +78,27 @@ func createCombinedLogReceiver(
}

if cfg.Logs.Enabled {
recv.logs = newMongoDBAtlasLogsReceiver(params, cfg, consumer)
recv.logs, err = newMongoDBAtlasLogsReceiver(params, cfg, consumer)
if err != nil {
return nil, fmt.Errorf("unable to create a MongoDB Atlas Logs Receiver instance: %w", err)
}
// Confirm at least one project is enabled for access logs before adding
for _, project := range cfg.Logs.Projects {
if project.AccessLogs != nil && project.AccessLogs.IsEnabled() {
recv.accessLogs = newAccessLogsReceiver(params, cfg, consumer)
recv.accessLogs, err = newAccessLogsReceiver(params, cfg, consumer)
if err != nil {
return nil, fmt.Errorf("unable to create a MongoDB Atlas Access Logs Receiver instance: %w", err)
}
break
}
}
}

if cfg.Events != nil {
recv.events = newEventsReceiver(params, cfg, consumer)
recv.events, err = newEventsReceiver(params, cfg, consumer)
if err != nil {
return nil, fmt.Errorf("unable to create a MongoDB Atlas Events Receiver instance: %w", err)
}
}

return recv, nil
Expand Down
17 changes: 14 additions & 3 deletions receiver/mongodbatlasreceiver/internal/mongodb_atlas_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,22 +130,33 @@ type MongoDBAtlasClient struct {

// NewMongoDBAtlasClient creates a new MongoDB Atlas client wrapper
func NewMongoDBAtlasClient(
baseURL string,
publicKey string,
privateKey string,
backoffConfig configretry.BackOffConfig,
log *zap.Logger,
) *MongoDBAtlasClient {
) (*MongoDBAtlasClient, error) {
defaultTransporter := http.DefaultTransport.(*http.Transport)
t := digest.NewTransportWithHTTPTransport(publicKey, privateKey, defaultTransporter)
roundTripper := newClientRoundTripper(t, log, backoffConfig)
tc := &http.Client{Transport: roundTripper}
client := mongodbatlas.NewClient(tc)

if baseURL == "" {
baseURL = mongodbatlas.CloudURL
}

client, err := mongodbatlas.New(tc, mongodbatlas.SetBaseURL(baseURL))
if err != nil {
log.Error("Failed to create client", zap.Error(err))
return nil, fmt.Errorf("failed to create MongoDB Atlas client: %w", err) // Return nil and the error
}

return &MongoDBAtlasClient{
log,
client,
defaultTransporter,
roundTripper,
}
}, nil
}

func (s *MongoDBAtlasClient) Shutdown() error {
Expand Down
10 changes: 7 additions & 3 deletions receiver/mongodbatlasreceiver/logs.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package mongodbatlasreceiver // import "github.com/open-telemetry/opentelemetry-
import (
"context"
"errors"
"fmt"
"io"
"net"
"strings"
Expand Down Expand Up @@ -43,8 +44,11 @@ type projectContext struct {
// MongoDB Atlas Documentation recommends a polling interval of 5 minutes: https://www.mongodb.com/docs/atlas/reference/api/logs/#logs
const collectionInterval = time.Minute * 5

func newMongoDBAtlasLogsReceiver(settings rcvr.Settings, cfg *Config, consumer consumer.Logs) *logsReceiver {
client := internal.NewMongoDBAtlasClient(cfg.PublicKey, string(cfg.PrivateKey), cfg.BackOffConfig, settings.Logger)
func newMongoDBAtlasLogsReceiver(settings rcvr.Settings, cfg *Config, consumer consumer.Logs) (*logsReceiver, error) {
client, err := internal.NewMongoDBAtlasClient(cfg.BaseURL, cfg.PublicKey, string(cfg.PrivateKey), cfg.BackOffConfig, settings.Logger)
if err != nil {
return nil, fmt.Errorf("failed to create MongoDB Atlas client for logs receiver: %w", err)
}

for _, p := range cfg.Logs.Projects {
p.populateIncludesAndExcludes()
Expand All @@ -56,7 +60,7 @@ func newMongoDBAtlasLogsReceiver(settings rcvr.Settings, cfg *Config, consumer c
client: client,
stopperChan: make(chan struct{}),
consumer: consumer,
}
}, nil
}

// Log receiver logic
Expand Down
10 changes: 7 additions & 3 deletions receiver/mongodbatlasreceiver/receiver.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,12 @@ type timeconstraints struct {
resolution string
}

func newMongoDBAtlasReceiver(settings receiver.Settings, cfg *Config) *mongodbatlasreceiver {
client := internal.NewMongoDBAtlasClient(cfg.PublicKey, string(cfg.PrivateKey), cfg.BackOffConfig, settings.Logger)
func newMongoDBAtlasReceiver(settings receiver.Settings, cfg *Config) (*mongodbatlasreceiver, error) {
client, err := internal.NewMongoDBAtlasClient(cfg.BaseURL, cfg.PublicKey, string(cfg.PrivateKey), cfg.BackOffConfig, settings.Logger)
if err != nil {
return nil, fmt.Errorf("failed to create MongoDB Atlas client receiver: %w", err)
}

for _, p := range cfg.Projects {
p.populateIncludesAndExcludes()
}
Expand All @@ -47,7 +51,7 @@ func newMongoDBAtlasReceiver(settings receiver.Settings, cfg *Config) *mongodbat
client: client,
mb: metadata.NewMetricsBuilder(cfg.MetricsBuilderConfig, settings),
stopperChan: make(chan struct{}),
}
}, nil
}

func newMongoDBAtlasScraper(recv *mongodbatlasreceiver) (scraper.Metrics, error) {
Expand Down
Loading