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/ntp] add initial implementation #35850

Merged
merged 2 commits into from
Oct 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
19 changes: 19 additions & 0 deletions receiver/ntpreceiver/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@
package ntpreceiver // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/ntpreceiver"

import (
"errors"
"fmt"
"net"
"time"

"go.opentelemetry.io/collector/receiver/scraperhelper"

"github.com/open-telemetry/opentelemetry-collector-contrib/receiver/ntpreceiver/internal/metadata"
Expand All @@ -13,5 +18,19 @@ import (
type Config struct {
scraperhelper.ControllerConfig `mapstructure:",squash"`
metadata.MetricsBuilderConfig `mapstructure:",squash"`
Version int `mapstructure:"version"`
Endpoint string `mapstructure:"endpoint"`
}

func (c *Config) Validate() error {
var errs []error
_, _, err := net.SplitHostPort(c.Endpoint)
if err != nil {
errs = append(errs, err)
}
// respect terms of service https://www.pool.ntp.org/tos.html
if c.ControllerConfig.CollectionInterval < 30*time.Minute {
errs = append(errs, fmt.Errorf("collection interval %v is less than minimum 30m", c.ControllerConfig.CollectionInterval))
}
return errors.Join(errs...)
}
65 changes: 65 additions & 0 deletions receiver/ntpreceiver/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

package ntpreceiver

import (
"testing"
"time"

"github.com/stretchr/testify/require"
"go.opentelemetry.io/collector/receiver/scraperhelper"
)

func TestValidate(t *testing.T) {
for _, tt := range []struct {
name string
c *Config
errorExpected string
}{
{
name: "no host",
c: &Config{
Version: 4,
Endpoint: "",
ControllerConfig: scraperhelper.ControllerConfig{CollectionInterval: 45 * time.Minute},
},
errorExpected: "missing port in address",
},
{
name: "no port",
c: &Config{
Version: 4,
Endpoint: "pool.ntp.org",
ControllerConfig: scraperhelper.ControllerConfig{CollectionInterval: 45 * time.Minute},
},
errorExpected: "address pool.ntp.org: missing port in address",
},
{
name: "valid",
c: &Config{
Version: 4,
Endpoint: "pool.ntp.org:123",
ControllerConfig: scraperhelper.ControllerConfig{CollectionInterval: 45 * time.Minute},
},
},
{
name: "interval too small",
c: &Config{
Version: 4,
Endpoint: "pool.ntp.org:123",
ControllerConfig: scraperhelper.ControllerConfig{CollectionInterval: 29 * time.Minute},
},
errorExpected: "collection interval 29m0s is less than minimum 30m",
},
} {
t.Run(tt.name, func(t *testing.T) {
err := tt.c.Validate()
if tt.errorExpected == "" {
require.NoError(t, err)
} else {
require.EqualError(t, err, tt.errorExpected)
}
})
}
}
4 changes: 2 additions & 2 deletions receiver/ntpreceiver/documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ metrics:

### ntp.offset

Time difference between local and NTP server clocks in seconds.
Time difference between local and NTP server clocks

| Unit | Metric Type | Value Type |
| ---- | ----------- | ---------- |
| s | Gauge | Int |
| ns | Gauge | Int |

## Resource Attributes

Expand Down
24 changes: 21 additions & 3 deletions receiver/ntpreceiver/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package ntpreceiver // import "github.com/open-telemetry/opentelemetry-collector

import (
"context"
"time"

"go.opentelemetry.io/collector/component"
"go.opentelemetry.io/collector/consumer"
Expand All @@ -23,12 +24,29 @@ func NewFactory() receiver.Factory {
}

func createDefaultConfig() component.Config {
scraperConfig := scraperhelper.NewDefaultControllerConfig()
scraperConfig.CollectionInterval = 30 * time.Minute
return &Config{
ControllerConfig: scraperhelper.NewDefaultControllerConfig(),
ControllerConfig: scraperConfig,
MetricsBuilderConfig: metadata.DefaultMetricsBuilderConfig(),
Version: 4,
Endpoint: "pool.ntp.org:123",
}
}

func createMetricsReceiver(_ context.Context, _ receiver.Settings, _ component.Config, _ consumer.Metrics) (receiver.Metrics, error) {
return nil, nil
func createMetricsReceiver(_ context.Context, settings receiver.Settings, cfg component.Config, consumer consumer.Metrics) (receiver.Metrics, error) {
rCfg := cfg.(*Config)
mp := newScraper(rCfg, settings)
s, err := scraperhelper.NewScraper(metadata.Type, mp.scrape)
if err != nil {
return nil, err
}
opt := scraperhelper.AddScraper(s)

return scraperhelper.NewScraperControllerReceiver(
&rCfg.ControllerConfig,
settings,
consumer,
opt,
)
}
18 changes: 18 additions & 0 deletions receiver/ntpreceiver/factory_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

package ntpreceiver

import (
"testing"
"time"

"github.com/stretchr/testify/require"
)

func TestCreateDefaultConfig(t *testing.T) {
c := createDefaultConfig().(*Config)
require.Equal(t, 4, c.Version)
require.Equal(t, "pool.ntp.org:123", c.Endpoint)
require.Equal(t, 30*time.Minute, c.CollectionInterval)
}
51 changes: 51 additions & 0 deletions receiver/ntpreceiver/generated_component_test.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion receiver/ntpreceiver/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ module github.com/open-telemetry/opentelemetry-collector-contrib/receiver/ntprec
go 1.22.0

require (
github.com/beevik/ntp v1.4.3
github.com/google/go-cmp v0.6.0
github.com/stretchr/testify v1.9.0
go.opentelemetry.io/collector/component v0.111.1-0.20241008154146-ea48c09c31ae
go.opentelemetry.io/collector/confmap v1.17.1-0.20241008154146-ea48c09c31ae
go.opentelemetry.io/collector/consumer v0.111.1-0.20241008154146-ea48c09c31ae
go.opentelemetry.io/collector/consumer/consumertest v0.111.1-0.20241008154146-ea48c09c31ae
go.opentelemetry.io/collector/filter v0.111.1-0.20241008154146-ea48c09c31ae
go.opentelemetry.io/collector/pdata v1.17.1-0.20241008154146-ea48c09c31ae
go.opentelemetry.io/collector/receiver v0.111.1-0.20241008154146-ea48c09c31ae
Expand All @@ -34,7 +36,6 @@ require (
github.com/rogpeppe/go-internal v1.12.0 // indirect
go.opentelemetry.io/collector/config/configtelemetry v0.111.1-0.20241008154146-ea48c09c31ae // indirect
go.opentelemetry.io/collector/consumer/consumerprofiles v0.111.1-0.20241008154146-ea48c09c31ae // indirect
go.opentelemetry.io/collector/consumer/consumertest v0.111.1-0.20241008154146-ea48c09c31ae // indirect
go.opentelemetry.io/collector/internal/globalsignal v0.111.1-0.20241008154146-ea48c09c31ae // indirect
go.opentelemetry.io/collector/pdata/pprofile v0.111.1-0.20241008154146-ea48c09c31ae // indirect
go.opentelemetry.io/collector/pipeline v0.111.1-0.20241008154146-ea48c09c31ae // indirect
Expand Down
2 changes: 2 additions & 0 deletions receiver/ntpreceiver/go.sum

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions receiver/ntpreceiver/internal/metadata/generated_metrics.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 3 additions & 5 deletions receiver/ntpreceiver/metadata.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,10 @@ resource_attributes:

metrics:
ntp.offset:
description: Time difference between local and NTP server clocks in seconds.
unit: "s"
description: Time difference between local and NTP server clocks
unit: "ns"
gauge:
value_type: int
enabled: true

tests:
skip_lifecycle: true
skip_shutdown: true
tests:
46 changes: 46 additions & 0 deletions receiver/ntpreceiver/receiver.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

package ntpreceiver // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/ntpreceiver"

import (
"context"
"time"

"github.com/beevik/ntp"
"go.opentelemetry.io/collector/pdata/pcommon"
"go.opentelemetry.io/collector/pdata/pmetric"
"go.opentelemetry.io/collector/receiver"
"go.uber.org/zap"

"github.com/open-telemetry/opentelemetry-collector-contrib/receiver/ntpreceiver/internal/metadata"
)

type scraper struct {
logger *zap.Logger
mb *metadata.MetricsBuilder
version int
timeout time.Duration
endpoint string
}

func (s *scraper) scrape(context.Context) (pmetric.Metrics, error) {
options := ntp.QueryOptions{Version: s.version, Timeout: s.timeout}
response, err := ntp.QueryWithOptions(s.endpoint, options)
if err != nil {
return pmetric.Metrics{}, err
}
s.mb.RecordNtpOffsetDataPoint(pcommon.NewTimestampFromTime(time.Now()), response.ClockOffset.Nanoseconds())
s.mb.NewResourceBuilder().SetNtpHost(s.endpoint)
return s.mb.Emit(), nil
}

func newScraper(cfg *Config, settings receiver.Settings) *scraper {
return &scraper{
logger: settings.TelemetrySettings.Logger,
mb: metadata.NewMetricsBuilder(cfg.MetricsBuilderConfig, settings),
version: cfg.Version,
timeout: cfg.ControllerConfig.Timeout,
endpoint: cfg.Endpoint,
}
}
Loading