-
Notifications
You must be signed in to change notification settings - Fork 2.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[ Chrony Receiver ] Part 1 - Adding initial component (#12101)
[ Chrony Receiver ] Adding initial component Adding in the conguration of the Chrony Receiver to be added along with the metadata metric configuration.
- Loading branch information
1 parent
a8b5fd0
commit 069d123
Showing
22 changed files
with
1,731 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
include ../../Makefile.Common |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
# Chrony Receiver | ||
|
||
| Status | | | ||
| ------------------------ | --------- | | ||
| Stability | [alpha] | | ||
| Supported pipeline types | metrics | | ||
| Distributions | [contrib] | | ||
|
||
The [chrony] receiver is a pure go implementation of the command `chronyc tracking` to allow for | ||
portability across systems and platforms. All of the data that would typically be captured by | ||
the tracking command is made available in this receiver, see [documentation](./documentation.md) for | ||
more details. | ||
|
||
## Configuration | ||
|
||
### Default | ||
|
||
By default, the `chrony` receiver will default to the following configuration: | ||
|
||
```yaml | ||
chrony/defaults: | ||
address: unix:///var/run/chrony/chronyd.sock # The default port by chronyd to allow cmd access | ||
timeout: 10s # Allowing at least 10s for chronyd to respond before giving up | ||
|
||
chrony: | ||
# This will result in the same configuration as above | ||
``` | ||
|
||
### Customised | ||
|
||
The following options can be customised: | ||
|
||
- address (required) - the address on where to communicate to `chronyd` | ||
- The allowed formats are the following | ||
- udp://hostname:port | ||
- unix:///path/to/chrony.sock (Please note the triple slash) | ||
- timeout (optional) - The total amount of time allowed to read and process the data from chronyd | ||
- Recommendation: This value should be set above 1s to allow `chronyd` time to respond | ||
- collection_interval (optional) - how frequent this receiver should poll [chrony] | ||
- metrics (optional) - Which metrics should be exported, read the [documentation] for complete details | ||
|
||
## Example | ||
|
||
An example of the configuration is: | ||
|
||
```yaml | ||
receivers: | ||
chrony: | ||
address: unix:///var/run/chrony/chronyd.sock | ||
timeout: 10s | ||
collection_interval: 30s | ||
metrics: | ||
ntp.skew: | ||
enabled: true | ||
ntp.stratum: | ||
enabled: true | ||
``` | ||
The complete list of metrics emitted by this receiver is found in the [documentation]. | ||
[alpha]: https://github.com/open-telemetry/opentelemetry-collector#alpha | ||
[contrib]: https://github.com/open-telemetry/opentelemetry-collector-releases/tree/main/distributions/otelcol-contrib | ||
[documentation]: ./documentation.md | ||
[chrony]: https://chrony.tuxfamily.org/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 chronyreceiver // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/chronyreceiver" | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"time" | ||
|
||
"go.opentelemetry.io/collector/config" | ||
"go.opentelemetry.io/collector/receiver/scraperhelper" | ||
|
||
"github.com/open-telemetry/opentelemetry-collector-contrib/receiver/chronyreceiver/internal/chrony" | ||
"github.com/open-telemetry/opentelemetry-collector-contrib/receiver/chronyreceiver/internal/metadata" | ||
) | ||
|
||
type Config struct { | ||
scraperhelper.ScraperControllerSettings `mapstructure:",squash"` | ||
metadata.MetricsSettings `mapstructure:"metrics"` | ||
// Endpoint is the published address or unix socket | ||
// that allows clients to connect to: | ||
// The allowed format is: | ||
// unix:///path/to/chronyd/unix.sock | ||
// udp://localhost:323 | ||
// | ||
// The default value is unix:///var/run/chrony/chronyd.sock | ||
Endpoint string `mapstructure:"endpoint"` | ||
// Timeout controls the max time allowed to read data from chronyd | ||
Timeout time.Duration `mapstructure:"timeout"` | ||
} | ||
|
||
var ( | ||
_ config.Receiver = (*Config)(nil) | ||
|
||
errInvalidValue = errors.New("invalid value") | ||
) | ||
|
||
func newDefaultCongfig() config.Receiver { | ||
return &Config{ | ||
ScraperControllerSettings: scraperhelper.NewDefaultScraperControllerSettings(typeStr), | ||
MetricsSettings: metadata.DefaultMetricsSettings(), | ||
|
||
Endpoint: "unix:///var/run/chrony/chronyd.sock", | ||
Timeout: 10 * time.Second, | ||
} | ||
} | ||
|
||
func (c *Config) Validate() error { | ||
if c.Timeout < 1 { | ||
return fmt.Errorf("must have a positive timeout: %w", errInvalidValue) | ||
} | ||
_, _, err := chrony.SplitNetworkEndpoint(c.Endpoint) | ||
return err | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
// 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 chronyreceiver | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"path" | ||
"testing" | ||
"time" | ||
|
||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
"go.opentelemetry.io/collector/component/componenttest" | ||
"go.opentelemetry.io/collector/config" | ||
"go.opentelemetry.io/collector/receiver/scraperhelper" | ||
"go.opentelemetry.io/collector/service/servicetest" | ||
|
||
"github.com/open-telemetry/opentelemetry-collector-contrib/receiver/chronyreceiver/internal/chrony" | ||
"github.com/open-telemetry/opentelemetry-collector-contrib/receiver/chronyreceiver/internal/metadata" | ||
) | ||
|
||
func TestLoadConfig(t *testing.T) { | ||
t.Parallel() | ||
|
||
factories, err := componenttest.NopFactories() | ||
require.NoError(t, err, "Must not error on creating Nop factories") | ||
|
||
factory := NewFactory() | ||
factories.Receivers[typeStr] = factory | ||
|
||
cfg, err := servicetest.LoadConfigAndValidate(path.Join("testdata", "config.yml"), factories) | ||
require.NoError(t, err, "Must not error when loading configuration") | ||
|
||
chronyConf := cfg.Receivers[config.NewComponentIDWithName(typeStr, "custom")] | ||
expect := &Config{ | ||
ScraperControllerSettings: scraperhelper.NewDefaultScraperControllerSettings(typeStr), | ||
MetricsSettings: metadata.DefaultMetricsSettings(), | ||
Endpoint: "udp://localhost:3030", | ||
Timeout: 10 * time.Second, | ||
} | ||
expect.SetIDName("custom") | ||
assert.Equal(t, expect, chronyConf) | ||
} | ||
|
||
func TestValidate(t *testing.T) { | ||
t.Parallel() | ||
|
||
tests := []struct { | ||
scenario string | ||
conf Config | ||
err error | ||
}{ | ||
{ | ||
scenario: "Valid udp configuration", | ||
conf: Config{ | ||
Endpoint: "udp://localhost:323", | ||
Timeout: 10 * time.Second, | ||
}, | ||
err: nil, | ||
}, | ||
{ | ||
scenario: "Invalid udp hostname", | ||
conf: Config{ | ||
Endpoint: "udp://:323", | ||
Timeout: 10 * time.Second, | ||
}, | ||
err: chrony.ErrInvalidNetwork, | ||
}, | ||
{ | ||
scenario: "Invalid udp port", | ||
conf: Config{ | ||
Endpoint: "udp://localhost", | ||
Timeout: 10 * time.Second, | ||
}, | ||
err: chrony.ErrInvalidNetwork, | ||
}, | ||
{ | ||
scenario: "Valid unix path", | ||
conf: Config{ | ||
Endpoint: fmt.Sprintf("unix://%s", t.TempDir()), | ||
Timeout: 10 * time.Second, | ||
}, | ||
err: nil, | ||
}, | ||
{ | ||
scenario: "Invalid unix path", | ||
conf: Config{ | ||
Endpoint: "unix:///no/dir/to/socket", | ||
Timeout: 10 * time.Second, | ||
}, | ||
err: os.ErrNotExist, | ||
}, | ||
{ | ||
scenario: "Invalid timeout set", | ||
conf: Config{ | ||
Endpoint: "unix://no/dir/to/socket", | ||
Timeout: 0, | ||
}, | ||
err: errInvalidValue, | ||
}, | ||
} | ||
|
||
for _, tc := range tests { | ||
t.Run(tc.scenario, func(t *testing.T) { | ||
assert.ErrorIs(t, tc.conf.Validate(), tc.err, "Must match the expected error") | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
// 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. | ||
|
||
//go:generate mdatagen --experimental-gen metadata.yaml | ||
package chronyreceiver // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/chronyreceiver" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
[comment]: <> (Code generated by mdatagen. DO NOT EDIT.) | ||
|
||
# chrony receiver | ||
|
||
## Metrics | ||
|
||
These are the metrics available for this scraper. | ||
|
||
| Name | Description | Unit | Type | Attributes | | ||
| ---- | ----------- | ---- | ---- | ---------- | | ||
| ntp.frequency.offset | The frequency is the rate by which the system s clock would be wrong if chronyd was not correcting it. It is expressed in ppm (parts per million). For example, a value of 1 ppm would mean that when the system’s clock thinks it has advanced 1 second, it has actually advanced by 1.000001 seconds relative to true time. | ppm | Gauge(Double) | <ul> <li>leap.status</li> </ul> | | ||
| **ntp.skew** | This is the estimated error bound on the frequency. | ppm | Gauge(Double) | <ul> </ul> | | ||
| ntp.stratum | The number of hops away from the reference system keeping the reference time To read further, refer to https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/system_administrators_guide/ch-configuring_ntp_using_the_chrony_suite#sect-Checking_chrony_tracking | {count} | Gauge(Int) | <ul> </ul> | | ||
| **ntp.time.correction** | The number of seconds difference between the system's clock and the reference clock | seconds | Gauge(Double) | <ul> <li>leap.status</li> </ul> | | ||
| **ntp.time.last_offset** | The estimated local offset on the last clock update | seconds | Gauge(Double) | <ul> <li>leap.status</li> </ul> | | ||
| ntp.time.rms_offset | the long term average of the offset value | seconds | Gauge(Double) | <ul> <li>leap.status</li> </ul> | | ||
| ntp.time.root_delay | This is the total of the network path delays to the stratum-1 system from which the system is ultimately synchronised. | seconds | Gauge(Double) | <ul> <li>leap.status</li> </ul> | | ||
|
||
**Highlighted metrics** are emitted by default. Other metrics are optional and not emitted by default. | ||
Any metric can be enabled or disabled with the following scraper configuration: | ||
|
||
```yaml | ||
metrics: | ||
<metric_name>: | ||
enabled: <true|false> | ||
``` | ||
## Metric attributes | ||
| Name | Description | Values | | ||
| ---- | ----------- | ------ | | ||
| leap.status | how the chrony is handling leap seconds | normal, insert_second, delete_second, unsynchronised | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
// 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 chronyreceiver // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/chronyreceiver" | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
|
||
"go.opentelemetry.io/collector/component" | ||
"go.opentelemetry.io/collector/config" | ||
"go.opentelemetry.io/collector/consumer" | ||
"go.opentelemetry.io/collector/receiver/scraperhelper" | ||
) | ||
|
||
const ( | ||
typeStr = "chrony" | ||
) | ||
|
||
func NewFactory() component.ReceiverFactory { | ||
return component.NewReceiverFactory( | ||
typeStr, | ||
newDefaultCongfig, | ||
component.WithMetricsReceiver(newMetricsReceiver), | ||
) | ||
} | ||
|
||
func newMetricsReceiver( | ||
ctx context.Context, | ||
set component.ReceiverCreateSettings, | ||
rCfg config.Receiver, | ||
consumer consumer.Metrics) (component.MetricsReceiver, error) { | ||
cfg, ok := rCfg.(*Config) | ||
if !ok { | ||
return nil, fmt.Errorf("wrong config provided: %w", errInvalidValue) | ||
} | ||
|
||
scraper, err := scraperhelper.NewScraper( | ||
typeStr, | ||
newScraper(ctx, cfg, set).scrape, | ||
) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return scraperhelper.NewScraperControllerReceiver( | ||
&cfg.ScraperControllerSettings, | ||
set, | ||
consumer, | ||
scraperhelper.AddScraper(scraper), | ||
) | ||
} |
Oops, something went wrong.