Skip to content

Commit

Permalink
[receiver/tcpcheck] New receiver
Browse files Browse the repository at this point in the history
Introduce a new receiver, TCP Check Receiver.This receiver creates stats by connecting to an TCP server.

Related to #34414

N/A

metadata.yaml, README.

Signed-off-by: huangyanfeng <huangyanfeng1992@gmail.com>
  • Loading branch information
yanfeng1992 committed Nov 21, 2024
1 parent b6b8679 commit 229051c
Show file tree
Hide file tree
Showing 33 changed files with 1,789 additions and 0 deletions.
27 changes: 27 additions & 0 deletions .chloggen/tcp-checker.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: new_component

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

# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
note: Introducing new component tcpcheck receiver

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

# (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: []
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,7 @@ receiver/sshcheckreceiver/ @open-telemetry/collector-cont
receiver/statsdreceiver/ @open-telemetry/collector-contrib-approvers @jmacd @dmitryax
receiver/syslogreceiver/ @open-telemetry/collector-contrib-approvers @djaglowski @andrzej-stencel
receiver/systemdreceiver/ @open-telemetry/collector-contrib-approvers @Hemansh31 @atoulme
receiver/tcpcheckreceiver/ @open-telemetry/collector-contrib-approvers @atoulme @yanfeng1992
receiver/tcplogreceiver/ @open-telemetry/collector-contrib-approvers @djaglowski
receiver/tlscheckreceiver/ @open-telemetry/collector-contrib-approvers @atoulme @michael-burt
receiver/udplogreceiver/ @open-telemetry/collector-contrib-approvers @djaglowski
Expand Down
1 change: 1 addition & 0 deletions .github/ISSUE_TEMPLATE/bug_report.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,7 @@ body:
- receiver/statsd
- receiver/syslog
- receiver/systemd
- receiver/tcpcheck
- receiver/tcplog
- receiver/tlscheck
- receiver/udplog
Expand Down
1 change: 1 addition & 0 deletions .github/ISSUE_TEMPLATE/feature_request.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@ body:
- receiver/statsd
- receiver/syslog
- receiver/systemd
- receiver/tcpcheck
- receiver/tcplog
- receiver/tlscheck
- receiver/udplog
Expand Down
1 change: 1 addition & 0 deletions .github/ISSUE_TEMPLATE/other.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@ body:
- receiver/statsd
- receiver/syslog
- receiver/systemd
- receiver/tcpcheck
- receiver/tcplog
- receiver/tlscheck
- receiver/udplog
Expand Down
1 change: 1 addition & 0 deletions .github/ISSUE_TEMPLATE/unmaintained.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,7 @@ body:
- receiver/statsd
- receiver/syslog
- receiver/systemd
- receiver/tcpcheck
- receiver/tcplog
- receiver/tlscheck
- receiver/udplog
Expand Down
1 change: 1 addition & 0 deletions receiver/tcpcheckreceiver/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include ../../Makefile.Common
44 changes: 44 additions & 0 deletions receiver/tcpcheckreceiver/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# TCP Check Receiver

<!-- status autogenerated section -->
| Status | |
| ------------- |-----------|
| Stability | [development]: metrics |
| Distributions | [contrib] |
| Issues | [![Open issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector-contrib?query=is%3Aissue%20is%3Aopen%20label%3Areceiver%2Ftcpcheck%20&label=open&color=orange&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues?q=is%3Aopen+is%3Aissue+label%3Areceiver%2Ftcpcheck) [![Closed issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector-contrib?query=is%3Aissue%20is%3Aclosed%20label%3Areceiver%2Ftcpcheck%20&label=closed&color=blue&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues?q=is%3Aclosed+is%3Aissue+label%3Areceiver%2Ftcpcheck) |
| [Code Owners](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/CONTRIBUTING.md#becoming-a-code-owner) | [@atoulme](https://www.github.com/atoulme), [@yanfeng1992](https://www.github.com/yanfeng1992) |

[development]: https://github.com/open-telemetry/opentelemetry-collector#development
[contrib]: https://github.com/open-telemetry/opentelemetry-collector-releases/tree/main/distributions/otelcol-contrib
<!-- end autogenerated section -->

This receiver creates stats by connecting to an TCP server.


## Configuration

The following settings are required:
- `endpoint`



The following settings are optional:

- `collection_interval` (default = `60s`): This receiver collects metrics on an interval. Valid time units are `ns`, `us` (or `µs`), `ms`, `s`, `m`, `h`.


### Example Configuration

```yaml
receivers:
sshcheck:
endpoint: localhost:80
collection_interval: 60s
```
The full list of settings exposed for this receiver are documented [here](./config.go) with detailed sample configurations [here](./testdata/config.yaml).
## Metrics
Details about the metrics produced by this receiver can be found in [metadata.yaml](./metadata.yaml)
40 changes: 40 additions & 0 deletions receiver/tcpcheckreceiver/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

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

import (
"errors"
"net"
"strings"

"go.opentelemetry.io/collector/receiver/scraperhelper"
"go.uber.org/multierr"

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

// Predefined error responses for configuration validation failures
var (
errMissingEndpoint = errors.New(`"endpoint" not specified in config`)
errInvalidEndpoint = errors.New(`"endpoint" is invalid`)
errConfigNotTCPCheck = errors.New("config was not a TCP check receiver config")
)

type Config struct {
scraperhelper.ControllerConfig `mapstructure:",squash"`
configtcp.TCPClientSettings `mapstructure:",squash"`
MetricsBuilderConfig metadata.MetricsBuilderConfig `mapstructure:",squash"`
}

func (c Config) Validate() (err error) {
if c.TCPClientSettings.Endpoint == "" {
err = multierr.Append(err, errMissingEndpoint)
} else if strings.Contains(c.TCPClientSettings.Endpoint, " ") {
err = multierr.Append(err, errInvalidEndpoint)
} else if _, _, splitErr := net.SplitHostPort(c.TCPClientSettings.Endpoint); splitErr != nil {
err = multierr.Append(splitErr, errInvalidEndpoint)
}
return
}
105 changes: 105 additions & 0 deletions receiver/tcpcheckreceiver/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

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

import (
"path/filepath"
"testing"
"time"

"github.com/stretchr/testify/require"
"go.opentelemetry.io/collector/component/componenttest"
"go.opentelemetry.io/collector/confmap/confmaptest"
"go.opentelemetry.io/collector/receiver/scraperhelper"
"go.uber.org/multierr"

"github.com/open-telemetry/opentelemetry-collector-contrib/receiver/tcpcheckreceiver/internal/configtcp"
)

// check that OTel Collector patterns are implemented
func TestCheckConfig(t *testing.T) {
t.Parallel()
if err := componenttest.CheckConfigStruct(&Config{}); err != nil {
t.Fatal(err)
}
}

// test the validate function for config
func TestValidate(t *testing.T) {
t.Parallel()
testCases := []struct {
desc string
cfg *Config
expectedErr error
}{
{
desc: "missing endpoint",
cfg: &Config{
TCPClientSettings: configtcp.TCPClientSettings{
Endpoint: "",
},
ControllerConfig: scraperhelper.NewDefaultControllerConfig(),
},
expectedErr: multierr.Combine(errMissingEndpoint),
},
{
desc: "invalid endpoint",
cfg: &Config{
TCPClientSettings: configtcp.TCPClientSettings{
Endpoint: "badendpoint . cuz spaces:443",
},
ControllerConfig: scraperhelper.NewDefaultControllerConfig(),
},
expectedErr: multierr.Combine(errInvalidEndpoint),
},
{
desc: "no error",
cfg: &Config{
TCPClientSettings: configtcp.TCPClientSettings{
Endpoint: "localhost:8080",
},
ControllerConfig: scraperhelper.NewDefaultControllerConfig(),
},
expectedErr: error(nil),
},
}
for _, tc := range testCases {
t.Run(tc.desc, func(t *testing.T) {
actualErr := tc.cfg.Validate()
if tc.expectedErr != nil {
require.EqualError(t, actualErr, tc.expectedErr.Error())
} else {
require.NoError(t, actualErr)
}
})
}
}

func TestLoadConfig(t *testing.T) {
// load test config
cm, err := confmaptest.LoadConf(filepath.Join("testdata", "config.yaml"))
require.NoError(t, err)
rcvrs, err := cm.Sub("receivers")
require.NoError(t, err)
tcpconf, err := rcvrs.Sub("tcpcheck")
require.NoError(t, err)
// unmarshal to receiver config
actualConfig, ok := NewFactory().CreateDefaultConfig().(*Config)
require.True(t, ok)
require.NoError(t, tcpconf.Unmarshal(actualConfig))

// set expected config
expectedConfig, ok := NewFactory().CreateDefaultConfig().(*Config)
require.True(t, ok)

expectedConfig.ControllerConfig = scraperhelper.ControllerConfig{
InitialDelay: time.Second,
CollectionInterval: 60 * time.Second,
}
expectedConfig.TCPClientSettings = configtcp.TCPClientSettings{
Endpoint: "localhost:80",
Timeout: 10 * time.Second,
}
require.Equal(t, expectedConfig, actualConfig)
}
6 changes: 6 additions & 0 deletions receiver/tcpcheckreceiver/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

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

//go:generate mdatagen metadata.yaml
56 changes: 56 additions & 0 deletions receiver/tcpcheckreceiver/documentation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
[comment]: <> (Code generated by mdatagen. DO NOT EDIT.)

# tcpcheck

## Default Metrics

The following metrics are emitted by default. Each of them can be disabled by applying the following configuration:

```yaml
metrics:
<metric_name>:
enabled: false
```
### tcpcheck.duration
Measures the duration of TCP connection.
| Unit | Metric Type | Value Type |
| ---- | ----------- | ---------- |
| ns | Gauge | Int |
#### Attributes
| Name | Description | Values |
| ---- | ----------- | ------ |
| tcp.endpoint | Full TCP endpoint | Any Str |
### tcpcheck.error
Records errors occurring during TCP check.
| Unit | Metric Type | Value Type | Aggregation Temporality | Monotonic |
| ---- | ----------- | ---------- | ----------------------- | --------- |
| {error} | Sum | Int | Cumulative | true |
#### Attributes
| Name | Description | Values |
| ---- | ----------- | ------ |
| tcp.endpoint | Full TCP endpoint | Any Str |
| error.message | Error message recorded during check | Any Str |
### tcpcheck.status
1 if the TCP client successfully connected, otherwise 0.
| Unit | Metric Type | Value Type |
| ---- | ----------- | ---------- |
| 1 | Gauge | Int |
#### Attributes
| Name | Description | Values |
| ---- | ----------- | ------ |
| tcp.endpoint | Full TCP endpoint | Any Str |
53 changes: 53 additions & 0 deletions receiver/tcpcheckreceiver/factory.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

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

import (
"context"
"time"

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

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

// NewFactory creates a factory for tcpcheckreceiver receiver.
func NewFactory() receiver.Factory {
return receiver.NewFactory(
metadata.Type,
createDefaultConfig,
receiver.WithMetrics(createMetricsReceiver, metadata.MetricsStability))
}

func createDefaultConfig() component.Config {
cfg := scraperhelper.NewDefaultControllerConfig()
cfg.CollectionInterval = 10 * time.Second

return &Config{
ControllerConfig: cfg,
TCPClientSettings: configtcp.TCPClientSettings{
Timeout: 10 * time.Second,
},
MetricsBuilderConfig: metadata.DefaultMetricsBuilderConfig(),
}
}

func createMetricsReceiver(_ context.Context, params receiver.Settings, rConf component.Config, consumer consumer.Metrics) (receiver.Metrics, error) {
cfg, ok := rConf.(*Config)
if !ok {
return nil, errConfigNotTCPCheck
}

tcpCheckScraper := newScraper(cfg, params)
scraper, err := scraperhelper.NewScraper(metadata.Type, tcpCheckScraper.scrape, scraperhelper.WithStart(tcpCheckScraper.start))
if err != nil {
return nil, err
}

return scraperhelper.NewScraperControllerReceiver(&cfg.ControllerConfig, params, consumer, scraperhelper.AddScraper(scraper))
}
Loading

0 comments on commit 229051c

Please sign in to comment.