Skip to content

Commit

Permalink
[httpcheckreceiver] new receiver (#14191)
Browse files Browse the repository at this point in the history
The HTTP Check Receiver can be used for synthethic checks against HTTP endpoints. This receiver will make a request to the specified `endpoint` using the configured `method`.

Fixes #10607
  • Loading branch information
Alex Boten authored Oct 18, 2022
1 parent 87e3a66 commit bf9686b
Show file tree
Hide file tree
Showing 24 changed files with 2,216 additions and 0 deletions.
16 changes: 16 additions & 0 deletions .chloggen/httpcheckreceiver.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# 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: httpcheckreceiver

# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
note: "New HTTP Check receiver allows users to run synthethic checks from the collector"

# One or more tracking issues related to the change
issues: [10607]

# (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:
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ receiver/fluentforwardreceiver/ @open-telemetry/collector-c
receiver/googlecloudpubsubreceiver/ @open-telemetry/collector-contrib-approvers @alexvanboxel
receiver/googlecloudspannerreceiver/ @open-telemetry/collector-contrib-approvers @ydrozhdzhal @asukhyy @khospodarysko @architjugran
receiver/hostmetricsreceiver/ @open-telemetry/collector-contrib-approvers @dmitryax
receiver/httpcheckreceiver/ @open-telemetry/collector-contrib-approvers @codeboten
receiver/influxdbreceiver/ @open-telemetry/collector-contrib-approvers @jacobmarble
receiver/iisreceiver/ @open-telemetry/collector-contrib-approvers @mrod1598 @djaglowski
receiver/jaegerreceiver/ @open-telemetry/collector-contrib-approvers @jpkrohling
Expand Down
3 changes: 3 additions & 0 deletions cmd/configschema/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,7 @@ require (
github.com/open-telemetry/opentelemetry-collector-contrib/receiver/googlecloudpubsubreceiver v0.62.0 // indirect
github.com/open-telemetry/opentelemetry-collector-contrib/receiver/googlecloudspannerreceiver v0.62.0 // indirect
github.com/open-telemetry/opentelemetry-collector-contrib/receiver/hostmetricsreceiver v0.62.0 // indirect
github.com/open-telemetry/opentelemetry-collector-contrib/receiver/httpcheckreceiver v0.0.0-00010101000000-000000000000 // indirect
github.com/open-telemetry/opentelemetry-collector-contrib/receiver/iisreceiver v0.62.0 // indirect
github.com/open-telemetry/opentelemetry-collector-contrib/receiver/influxdbreceiver v0.62.0 // indirect
github.com/open-telemetry/opentelemetry-collector-contrib/receiver/jaegerreceiver v0.62.0 // indirect
Expand Down Expand Up @@ -907,6 +908,8 @@ replace github.com/open-telemetry/opentelemetry-collector-contrib/receiver/googl

replace github.com/open-telemetry/opentelemetry-collector-contrib/receiver/hostmetricsreceiver => ../../receiver/hostmetricsreceiver

replace github.com/open-telemetry/opentelemetry-collector-contrib/receiver/httpcheckreceiver => ../../receiver/httpcheckreceiver

replace github.com/open-telemetry/opentelemetry-collector-contrib/receiver/influxdbreceiver => ../../receiver/influxdbreceiver

replace github.com/open-telemetry/opentelemetry-collector-contrib/receiver/iisreceiver => ../../receiver/iisreceiver
Expand Down
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ require (
github.com/open-telemetry/opentelemetry-collector-contrib/receiver/googlecloudpubsubreceiver v0.62.0
github.com/open-telemetry/opentelemetry-collector-contrib/receiver/googlecloudspannerreceiver v0.62.0
github.com/open-telemetry/opentelemetry-collector-contrib/receiver/hostmetricsreceiver v0.62.0
github.com/open-telemetry/opentelemetry-collector-contrib/receiver/httpcheckreceiver v0.0.0-00010101000000-000000000000
github.com/open-telemetry/opentelemetry-collector-contrib/receiver/iisreceiver v0.62.0
github.com/open-telemetry/opentelemetry-collector-contrib/receiver/influxdbreceiver v0.62.0
github.com/open-telemetry/opentelemetry-collector-contrib/receiver/jaegerreceiver v0.62.0
Expand Down Expand Up @@ -906,6 +907,8 @@ replace github.com/open-telemetry/opentelemetry-collector-contrib/receiver/googl

replace github.com/open-telemetry/opentelemetry-collector-contrib/receiver/hostmetricsreceiver => ./receiver/hostmetricsreceiver

replace github.com/open-telemetry/opentelemetry-collector-contrib/receiver/httpcheckreceiver => ./receiver/httpcheckreceiver

replace github.com/open-telemetry/opentelemetry-collector-contrib/receiver/influxdbreceiver => ./receiver/influxdbreceiver

replace github.com/open-telemetry/opentelemetry-collector-contrib/receiver/iisreceiver => ./receiver/iisreceiver
Expand Down
2 changes: 2 additions & 0 deletions internal/components/components.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ import (
"github.com/open-telemetry/opentelemetry-collector-contrib/receiver/googlecloudpubsubreceiver"
"github.com/open-telemetry/opentelemetry-collector-contrib/receiver/googlecloudspannerreceiver"
"github.com/open-telemetry/opentelemetry-collector-contrib/receiver/hostmetricsreceiver"
"github.com/open-telemetry/opentelemetry-collector-contrib/receiver/httpcheckreceiver"
"github.com/open-telemetry/opentelemetry-collector-contrib/receiver/iisreceiver"
"github.com/open-telemetry/opentelemetry-collector-contrib/receiver/influxdbreceiver"
"github.com/open-telemetry/opentelemetry-collector-contrib/receiver/jaegerreceiver"
Expand Down Expand Up @@ -231,6 +232,7 @@ func Components() (component.Factories, error) {
googlecloudspannerreceiver.NewFactory(),
googlecloudpubsubreceiver.NewFactory(),
hostmetricsreceiver.NewFactory(),
httpcheckreceiver.NewFactory(),
influxdbreceiver.NewFactory(),
iisreceiver.NewFactory(),
jaegerreceiver.NewFactory(),
Expand Down
3 changes: 3 additions & 0 deletions internal/components/receivers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,9 @@ func TestDefaultReceivers(t *testing.T) {
{
receiver: "hostmetrics",
},
{
receiver: "httpcheck",
},
{
receiver: "influxdb",
},
Expand Down
1 change: 1 addition & 0 deletions receiver/httpcheckreceiver/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include ../../Makefile.Common
47 changes: 47 additions & 0 deletions receiver/httpcheckreceiver/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# HTTP Check Receiver

| Status | |
| ------------------------ |------------------|
| Stability | [in development] |
| Supported pipeline types | metrics |
| Distributions | none |

The HTTP Check Receiver can be used for synthethic checks against HTTP endpoints. This receiver will make a request to the specified `endpoint` using the
configured `method`. This scraper generates a metric with a label for each HTTP response status class with a value of `1` if the status code matches the
class. For example, the following metrics will be generated if the endpoint returned a `200`:

```
httpcheck.status{http.status_class:1xx, http.status_code:200,...} = 0
httpcheck.status{http.status_class:2xx, http.status_code:200,...} = 1
httpcheck.status{http.status_class:3xx, http.status_code:200,...} = 0
httpcheck.status{http.status_class:4xx, http.status_code:200,...} = 0
httpcheck.status{http.status_class:5xx, http.status_code:200,...} = 0
```

## Configuration

The following configuration settings are required:

- `endpoint`: The URL of the endpoint to be monitored.

The following configuration settings are optional:

- `method` (default: `GET`): The method used to call the endpoint.
- `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:
http_check:
endpoint: http://endpoint:80
method: GET
collection_interval: 10s
```
## Metrics
Details about the metrics produced by this receiver can be found in [documentation.md](./documentation.md)
[in development]: https://github.com/open-telemetry/opentelemetry-collector#in-development
[contrib]: https://github.com/open-telemetry/opentelemetry-collector-releases/tree/main/distributions/otelcol-contrib
55 changes: 55 additions & 0 deletions receiver/httpcheckreceiver/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// 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 httpcheckreceiver // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/httpcheckreceiver"

import (
"errors"
"fmt"
"net/url"

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

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

// Predefined error responses for configuration validation failures
var (
errInvalidEndpoint = errors.New(`"endpoint" must be in the form of <scheme>://<hostname>:<port>`)
)

const defaultEndpoint = "http://localhost:80"

// Config defines the configuration for the various elements of the receiver agent.
type Config struct {
scraperhelper.ScraperControllerSettings `mapstructure:",squash"`
confighttp.HTTPClientSettings `mapstructure:",squash"`
Metrics metadata.MetricsSettings `mapstructure:"metrics"`
Method string `mapstructure:"method"`
}

// Validate validates the configuration by checking for missing or invalid fields
func (cfg *Config) Validate() error {
var err error

_, parseErr := url.Parse(cfg.Endpoint)
if parseErr != nil {
wrappedErr := fmt.Errorf("%s: %w", errInvalidEndpoint.Error(), parseErr)
err = multierr.Append(err, wrappedErr)
}

return err
}
66 changes: 66 additions & 0 deletions receiver/httpcheckreceiver/config_test.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 httpcheckreceiver // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/httpcheckreceiver"

import (
"errors"
"fmt"
"testing"

"github.com/stretchr/testify/require"
"go.opentelemetry.io/collector/config/confighttp"
"go.uber.org/multierr"
)

func TestValidate(t *testing.T) {
testCases := []struct {
desc string
cfg *Config
expectedErr error
}{
{
desc: "invalid endpoint",
cfg: &Config{
HTTPClientSettings: confighttp.HTTPClientSettings{
Endpoint: "invalid://endpoint: 12efg",
},
},
expectedErr: multierr.Combine(
fmt.Errorf("%s: %w", errInvalidEndpoint, errors.New(`parse "invalid://endpoint: 12efg": invalid port ": 12efg" after host`)),
),
},
{
desc: "valid config",
cfg: &Config{
HTTPClientSettings: confighttp.HTTPClientSettings{
Endpoint: defaultEndpoint,
},
},
expectedErr: 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)
}

})
}
}
17 changes: 17 additions & 0 deletions receiver/httpcheckreceiver/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// 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 metadata.yaml

package httpcheckreceiver // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/httpcheckreceiver"
32 changes: 32 additions & 0 deletions receiver/httpcheckreceiver/documentation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
[comment]: <> (Code generated by mdatagen. DO NOT EDIT.)

# httpcheckreceiver

## Metrics

These are the metrics available for this scraper.

| Name | Description | Unit | Type | Attributes |
| ---- | ----------- | ---- | ---- | ---------- |
| **httpcheck.duration** | Measures the duration of the HTTP check. | ms | Gauge(Int) | <ul> <li>http.url</li> </ul> |
| **httpcheck.error** | Records errors occurring during HTTP check. | {error} | Sum(Int) | <ul> <li>http.url</li> <li>error.message</li> </ul> |
| **httpcheck.status** | 1 if the check resulted in status_code matching the status_class, otherwise 0. | 1 | Sum(Int) | <ul> <li>http.url</li> <li>http.status_code</li> <li>http.method</li> <li>http.status_class</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 |
| ---- | ----------- | ------ |
| error.message | Error message recorded during check | |
| http.method | HTTP request method | |
| http.status_class | HTTP response status class | |
| http.status_code | HTTP response status code | |
| http.url | Full HTTP request URL. | |
74 changes: 74 additions & 0 deletions receiver/httpcheckreceiver/factory.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// 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 httpcheckreceiver // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/httpcheckreceiver"

import (
"context"
"errors"
"time"

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

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

const (
typeStr = "httpcheck"
stability = component.StabilityLevelInDevelopment
)

var errConfigNotHTTPCheck = errors.New("config was not a HTTP check receiver config")

// NewFactory creates a new receiver factory
func NewFactory() component.ReceiverFactory {
return component.NewReceiverFactory(
typeStr,
createDefaultConfig,
component.WithMetricsReceiver(createMetricsReceiver, stability))
}

func createDefaultConfig() config.Receiver {
return &Config{
ScraperControllerSettings: scraperhelper.ScraperControllerSettings{
ReceiverSettings: config.NewReceiverSettings(config.NewComponentID(typeStr)),
CollectionInterval: 10 * time.Second,
},
HTTPClientSettings: confighttp.HTTPClientSettings{
Endpoint: defaultEndpoint,
Timeout: 10 * time.Second,
},
Metrics: metadata.DefaultMetricsSettings(),
Method: "GET",
}
}

func createMetricsReceiver(ctx context.Context, params component.ReceiverCreateSettings, rConf config.Receiver, consumer consumer.Metrics) (component.MetricsReceiver, error) {
cfg, ok := rConf.(*Config)
if !ok {
return nil, errConfigNotHTTPCheck
}

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

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

0 comments on commit bf9686b

Please sign in to comment.