Skip to content
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

[receiver/mongodbatlasreceiver] Add Log collection #12800

Merged
merged 29 commits into from
Aug 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
993f0f5
initial commit to mongodb_atlas
armstrmi Jul 19, 2022
b859ab2
newly updated logs receiver functionality
armstrmi Jul 20, 2022
e3d31fc
removed redundant alert receiver create statement
armstrmi Jul 26, 2022
2b37938
correctly parsing out logs from clusters
armstrmi Jul 26, 2022
6a3f894
added logic for audit logs
armstrmi Jul 27, 2022
5d63636
add collection interval to the log collection method
armstrmi Jul 28, 2022
1f45f7b
added unit tests for functionality
armstrmi Aug 1, 2022
09782b7
edit README to include updated config
armstrmi Aug 1, 2022
001b1b2
implemented changes from feeback
armstrmi Aug 1, 2022
629c596
added necessary feedback for collection interval
armstrmi Aug 2, 2022
dc0ab22
implemented necessary feedback changes
armstrmi Aug 2, 2022
25003d1
incorporated start and end times to be included in the resourceInfo s…
armstrmi Aug 3, 2022
c28b738
added wait group to ensure client is shutdown properly
armstrmi Aug 3, 2022
a0c943f
Updated receiver_test to account for unique mongodb config IDs
armstrmi Aug 4, 2022
2f78216
add license and lint fixes
armstrmi Aug 4, 2022
46fa2c0
linter fixes
armstrmi Aug 4, 2022
97c899f
feedback changes
armstrmi Aug 4, 2022
e1f8f48
minor fixes before major fixes
armstrmi Aug 5, 2022
2b1f638
removed collection of organizations in KickoffReceiver
armstrmi Aug 8, 2022
5a89655
created separate logsReceiver struct
armstrmi Aug 9, 2022
ca42999
make goporto
armstrmi Aug 9, 2022
88f96c5
updated naming semantics
armstrmi Aug 10, 2022
04bf53c
updated test to account for no logging enabled
armstrmi Aug 10, 2022
2074604
enabled logging in component receiver test
armstrmi Aug 10, 2022
8d10f37
implemented feedback
armstrmi Aug 11, 2022
82a6d1f
implemented feedback for log conversion
armstrmi Aug 12, 2022
748057b
updated logrecord to populate only when logrecord is present
armstrmi Aug 12, 2022
733d681
removing unnecessary log statement
armstrmi Aug 12, 2022
d61e252
parameter name and logging statements update
armstrmi Aug 15, 2022
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
10 changes: 10 additions & 0 deletions internal/components/receivers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ import (
"errors"
"path/filepath"
"runtime"
"strconv"
"testing"
"time"

promconfig "github.com/prometheus/prometheus/config"
"github.com/stretchr/testify/assert"
Expand All @@ -38,6 +40,7 @@ import (
"github.com/open-telemetry/opentelemetry-collector-contrib/receiver/carbonreceiver"
"github.com/open-telemetry/opentelemetry-collector-contrib/receiver/chronyreceiver"
"github.com/open-telemetry/opentelemetry-collector-contrib/receiver/filelogreceiver"
"github.com/open-telemetry/opentelemetry-collector-contrib/receiver/mongodbatlasreceiver"
"github.com/open-telemetry/opentelemetry-collector-contrib/receiver/otlpjsonfilereceiver"
"github.com/open-telemetry/opentelemetry-collector-contrib/receiver/prometheusreceiver"
"github.com/open-telemetry/opentelemetry-collector-contrib/receiver/syslogreceiver"
Expand Down Expand Up @@ -198,6 +201,13 @@ func TestDefaultReceivers(t *testing.T) {
},
{
receiver: "mongodbatlas",
// MongoDB Atlas needs unique config IDs
getConfigFn: func() config.Receiver {
cfg := rcvrFactories["mongodbatlas"].CreateDefaultConfig().(*mongodbatlasreceiver.Config)
cfg.SetIDName(strconv.Itoa(int(time.Now().UnixNano())))
cfg.Logs.Enabled = true
return cfg
},
},
{
receiver: "mysql",
Expand Down
25 changes: 24 additions & 1 deletion receiver/mongodbatlasreceiver/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,14 @@ as well as alerts via a configured [webhook](https://www.mongodb.com/docs/atlas/
## Getting Started

The MongoDB Atlas receiver takes the following parameters. `public_key` and
`private_key` are the only two required values to receive metrics and are obtained via the
`private_key` are the only two required values to receive metrics and logs and are obtained via the
"API Keys" tab of the MongoDB Atlas Project Access Manager. In the example
below both values are being pulled from the environment.

In order to collect logs, at least one project must be specified. By default, logs for all clusters within a project will be collected. Clusters can be limited using either the `include_clusters` or `exclude_clusters` setting.

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

- `public_key` (required for metrics)
- `private_key` (required for metrics)
- `granularity` (default `PT1M` - See [MongoDB Atlas Documentation](https://docs.atlas.mongodb.com/reference/api/process-measurements/))
Expand All @@ -32,6 +36,14 @@ below both values are being pulled from the environment.
- `tls`
- `key_file`
- `cert_file`
- `logs`
- `enabled` (default false)
armstrmi marked this conversation as resolved.
Show resolved Hide resolved
- `projects` (required if enabled)
- `name` (required if enabled)
- `collect_audit_logs` (default false)
- `include_clusters` (default empty)
- `exclude_clusters` (default empty)


Examples:

Expand All @@ -53,5 +65,16 @@ receivers:
endpoint: "0.0.0.0:7706"
```

Receive logs:
```yaml
receivers:
mongodbatlas:
logs:
enabled: true
projects:
- name: "project 1"
collect_audit_logs: true
```

[beta]:https://github.com/open-telemetry/opentelemetry-collector#beta
[contrib]:https://github.com/open-telemetry/opentelemetry-collector-releases/tree/main/distributions/otelcol-contrib
66 changes: 66 additions & 0 deletions receiver/mongodbatlasreceiver/combined_logs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Copyright The OpenTelemetry Authors
//
// 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 mongodbatlasreceiver // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/mongodbatlasreceiver"

import (
"context"

"github.com/hashicorp/go-multierror"
"go.opentelemetry.io/collector/component"
)

// combindedLogsReceiver wraps alerts and log receivers in a single log receiver to be consumed by the factory
type combindedLogsReceiver struct {
alerts *alertsReceiver
logs *logsReceiver
}

// Starts up the combined MongoDB Atlas Logs and Alert Receiver
func (c *combindedLogsReceiver) Start(ctx context.Context, host component.Host) error {
var errs error

if c.alerts != nil {
if err := c.alerts.Start(ctx, host); err != nil {
errs = multierror.Append(errs, err)
}
}

if c.logs != nil {
if err := c.logs.Start(ctx, host); err != nil {
errs = multierror.Append(errs, err)
}
}

return errs
}

// Shutsdown the combined MongoDB Atlas Logs and Alert Receiver
func (c *combindedLogsReceiver) Shutdown(ctx context.Context) error {
var errs error

if c.alerts != nil {
if err := c.alerts.Shutdown(ctx); err != nil {
errs = multierror.Append(errs, err)
}
}

if c.logs != nil {
if err := c.logs.Shutdown(ctx); err != nil {
errs = multierror.Append(errs, err)
}
}

return errs
}
38 changes: 38 additions & 0 deletions receiver/mongodbatlasreceiver/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ type Config struct {
Granularity string `mapstructure:"granularity"`
Metrics metadata.MetricsSettings `mapstructure:"metrics"`
Alerts AlertConfig `mapstructure:"alerts"`
Logs LogConfig `mapstructure:"logs"`
RetrySettings exporterhelper.RetrySettings `mapstructure:"retry_on_failure"`
}

Expand All @@ -47,18 +48,55 @@ type AlertConfig struct {
TLS *configtls.TLSServerSetting `mapstructure:"tls"`
}

type LogConfig struct {
Enabled bool `mapstructure:"enabled"`
Projects []*ProjectConfig `mapstructure:"projects"`
}

type ProjectConfig struct {
Name string `mapstructure:"name"`
ExcludeClusters []string `mapstructure:"exclude_clusters"`
IncludeClusters []string `mapstructure:"include_clusters"`
EnableAuditLogs bool `mapstructure:"collect_audit_logs"`
}

var (
// Alerts Receiver Errors
errNoEndpoint = errors.New("an endpoint must be specified")
errNoSecret = errors.New("a webhook secret must be specified")
errNoCert = errors.New("tls was configured, but no cert file was specified")
errNoKey = errors.New("tls was configured, but no key file was specified")

// Logs Receiver Errors
errNoProjects = errors.New("at least one 'project' must be specified")
errClusterConfig = errors.New("only one of 'include_clusters' or 'exclude_clusters' may be specified")
)

func (c *Config) Validate() error {
var errs error

errs = multierr.Append(errs, c.ScraperControllerSettings.Validate())
errs = multierr.Append(errs, c.Alerts.validate())
errs = multierr.Append(errs, c.Logs.validate())

return errs
}

func (l *LogConfig) validate() error {
if !l.Enabled {
return nil
}

var errs error
if len(l.Projects) == 0 {
errs = multierr.Append(errs, errNoProjects)
}
armstrmi marked this conversation as resolved.
Show resolved Hide resolved

for _, project := range l.Projects {
if len(project.ExcludeClusters) != 0 && len(project.IncludeClusters) != 0 {
errs = multierr.Append(errs, errClusterConfig)
}
}

return errs
}
Expand Down
40 changes: 40 additions & 0 deletions receiver/mongodbatlasreceiver/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,46 @@ func TestValidate(t *testing.T) {
},
expectedErr: errNoCert.Error(),
},
{
name: "Valid Logs Config",
input: Config{
Logs: LogConfig{
Enabled: true,
Projects: []*ProjectConfig{
{
Name: "Project1",
EnableAuditLogs: false,
},
},
},
},
},
{
name: "Invalid Logs Config",
input: Config{
Logs: LogConfig{
Enabled: true,
},
},
expectedErr: errNoProjects.Error(),
},
{
name: "Invalid ProjectConfig",
input: Config{
Logs: LogConfig{
Enabled: true,
Projects: []*ProjectConfig{
{
Name: "Project1",
EnableAuditLogs: false,
ExcludeClusters: []string{"cluster1"},
IncludeClusters: []string{"cluster2"},
},
},
},
},
expectedErr: errClusterConfig.Error(),
},
}

for _, tc := range testCases {
Expand Down
41 changes: 35 additions & 6 deletions receiver/mongodbatlasreceiver/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package mongodbatlasreceiver // import "github.com/open-telemetry/opentelemetry-

import (
"context"
"errors"
"fmt"

"go.opentelemetry.io/collector/component"
Expand All @@ -32,6 +33,7 @@ const (
stability = component.StabilityLevelBeta
defaultGranularity = "PT1M" // 1-minute, as per https://docs.atlas.mongodb.com/reference/api/process-measurements/
defaultAlertsEnabled = false
defaultLogsEnabled = false
)

// NewFactory creates a factory for MongoDB Atlas receiver
Expand All @@ -40,7 +42,8 @@ func NewFactory() component.ReceiverFactory {
typeStr,
createDefaultConfig,
component.WithMetricsReceiver(createMetricsReceiver, stability),
component.WithLogsReceiver(createLogsReceiver, stability))
component.WithLogsReceiver(createCombinedLogReceiver, stability))

}

func createMetricsReceiver(
Expand All @@ -50,24 +53,46 @@ func createMetricsReceiver(
consumer consumer.Metrics,
) (component.MetricsReceiver, error) {
cfg := rConf.(*Config)
ms, err := newMongoDBAtlasScraper(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 Scaper instance: %w", err)
}

return scraperhelper.NewScraperControllerReceiver(&cfg.ScraperControllerSettings, params, consumer, scraperhelper.AddScraper(ms))
}

func createLogsReceiver(
func createCombinedLogReceiver(
_ context.Context,
params component.ReceiverCreateSettings,
rConf config.Receiver,
consumer consumer.Logs,
) (component.LogsReceiver, error) {
cfg := rConf.(*Config)
recv, err := newAlertsReceiver(params.Logger, cfg.Alerts, consumer)
if err != nil {
return nil, fmt.Errorf("unable to create a MongoDB Atlas Receiver instance: %w", err)

if !cfg.Alerts.Enabled && !cfg.Logs.Enabled {
return nil, errors.New("one of 'alerts' or 'logs' must be enabled")
}

var err error
recv := &combindedLogsReceiver{}

if cfg.Alerts.Enabled {
recv.alerts, err = newAlertsReceiver(params.Logger, cfg.Alerts, consumer)
djaglowski marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return nil, fmt.Errorf("unable to create a MongoDB Atlas Alerts Receiver instance: %w", err)
}
}

if cfg.Logs.Enabled {
djaglowski marked this conversation as resolved.
Show resolved Hide resolved
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)
}
}

return recv, nil
Expand All @@ -82,5 +107,9 @@ func createDefaultConfig() config.Receiver {
Alerts: AlertConfig{
Enabled: defaultAlertsEnabled,
},
Logs: LogConfig{
Enabled: defaultLogsEnabled,
Projects: []*ProjectConfig{},
},
}
}
Loading