Adding upstream version 1.34.4.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
e393c3af3f
commit
4978089aab
4963 changed files with 677545 additions and 0 deletions
62
plugins/outputs/logzio/README.md
Normal file
62
plugins/outputs/logzio/README.md
Normal file
|
@ -0,0 +1,62 @@
|
|||
# Logz.io Output Plugin
|
||||
|
||||
This plugin writes metrics to the [Logz.io][logzio] service via HTTP.
|
||||
|
||||
⭐ Telegraf v1.17.0
|
||||
🏷️ cloud, datastore
|
||||
💻 all
|
||||
|
||||
[logzio]: https://logz.io
|
||||
|
||||
## Global configuration options <!-- @/docs/includes/plugin_config.md -->
|
||||
|
||||
In addition to the plugin-specific configuration settings, plugins support
|
||||
additional global and plugin configuration settings. These settings are used to
|
||||
modify metrics, tags, and field or create aliases and configure ordering, etc.
|
||||
See the [CONFIGURATION.md][CONFIGURATION.md] for more details.
|
||||
|
||||
[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins
|
||||
|
||||
## Secret-store support
|
||||
|
||||
This plugin supports secrets from secret-stores for the `token` option.
|
||||
See the [secret-store documentation][SECRETSTORE] for more details on how
|
||||
to use them.
|
||||
|
||||
[SECRETSTORE]: ../../../docs/CONFIGURATION.md#secret-store-secrets
|
||||
|
||||
## Configuration
|
||||
|
||||
```toml @sample.conf
|
||||
# A plugin that can send metrics over HTTPs to Logz.io
|
||||
[[outputs.logzio]]
|
||||
## Connection timeout, defaults to "5s" if not set.
|
||||
# timeout = "5s"
|
||||
|
||||
## Optional TLS Config
|
||||
# tls_ca = "/etc/telegraf/ca.pem"
|
||||
# tls_cert = "/etc/telegraf/cert.pem"
|
||||
# tls_key = "/etc/telegraf/key.pem"
|
||||
|
||||
## Logz.io account token
|
||||
token = "your logz.io token" # required
|
||||
|
||||
## Use your listener URL for your Logz.io account region.
|
||||
# url = "https://listener.logz.io:8071"
|
||||
```
|
||||
|
||||
### Required parameters
|
||||
|
||||
Your Logz.io `token`, which can be found under "settings" in your account, is
|
||||
required.
|
||||
|
||||
### Optional parameters
|
||||
|
||||
- `check_disk_space`: Set to true if Logz.io sender checks the disk space before
|
||||
adding metrics to the disk queue.
|
||||
- `disk_threshold`: If the queue_dir space crosses this threshold
|
||||
(in % of disk usage), the plugin will start dropping logs.
|
||||
- `drain_duration`: Time to sleep between sending attempts.
|
||||
- `queue_dir`: Metrics disk path. All the unsent metrics are saved to the disk
|
||||
in this location.
|
||||
- `url`: Logz.io listener URL.
|
172
plugins/outputs/logzio/logzio.go
Normal file
172
plugins/outputs/logzio/logzio.go
Normal file
|
@ -0,0 +1,172 @@
|
|||
//go:generate ../../../tools/readme_config_includer/generator
|
||||
package logzio
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
_ "embed"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/influxdata/telegraf"
|
||||
"github.com/influxdata/telegraf/config"
|
||||
"github.com/influxdata/telegraf/plugins/common/tls"
|
||||
"github.com/influxdata/telegraf/plugins/outputs"
|
||||
)
|
||||
|
||||
//go:embed sample.conf
|
||||
var sampleConfig string
|
||||
|
||||
const (
|
||||
defaultLogzioURL = "https://listener.logz.io:8071"
|
||||
logzioType = "telegraf"
|
||||
)
|
||||
|
||||
type Logzio struct {
|
||||
URL string `toml:"url"`
|
||||
Token config.Secret `toml:"token"`
|
||||
Timeout config.Duration `toml:"timeout"`
|
||||
Log telegraf.Logger `toml:"-"`
|
||||
|
||||
tls.ClientConfig
|
||||
client *http.Client
|
||||
}
|
||||
|
||||
type TimeSeries struct {
|
||||
Series []*Metric
|
||||
}
|
||||
|
||||
type Metric struct {
|
||||
Metric map[string]interface{} `json:"metrics"`
|
||||
Dimensions map[string]string `json:"dimensions"`
|
||||
Time time.Time `json:"@timestamp"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
func (*Logzio) SampleConfig() string {
|
||||
return sampleConfig
|
||||
}
|
||||
|
||||
// Connect to the Output
|
||||
func (l *Logzio) Connect() error {
|
||||
l.Log.Debug("Connecting to logz.io output...")
|
||||
|
||||
if l.Token.Empty() {
|
||||
return errors.New("token is required")
|
||||
}
|
||||
if equal, err := l.Token.EqualTo([]byte("your logz.io token")); err != nil {
|
||||
return err
|
||||
} else if equal {
|
||||
return errors.New("please replace 'token' with your actual token")
|
||||
}
|
||||
|
||||
tlsCfg, err := l.ClientConfig.TLSConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
l.client = &http.Client{
|
||||
Transport: &http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
TLSClientConfig: tlsCfg,
|
||||
},
|
||||
Timeout: time.Duration(l.Timeout),
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close any connections to the Output
|
||||
func (l *Logzio) Close() error {
|
||||
l.Log.Debug("Closing logz.io output")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Write takes in group of points to be written to the Output
|
||||
func (l *Logzio) Write(metrics []telegraf.Metric) error {
|
||||
if len(metrics) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
var buff bytes.Buffer
|
||||
gz := gzip.NewWriter(&buff)
|
||||
for _, metric := range metrics {
|
||||
m := parseMetric(metric)
|
||||
|
||||
serialized, err := json.Marshal(m)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to marshal metric: %w", err)
|
||||
}
|
||||
|
||||
_, err = gz.Write(append(serialized, '\n'))
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to write gzip meric: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
err := gz.Close()
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to close gzip: %w", err)
|
||||
}
|
||||
|
||||
return l.send(buff.Bytes())
|
||||
}
|
||||
|
||||
func (l *Logzio) send(metrics []byte) error {
|
||||
url, err := l.authURL()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("POST", url, bytes.NewBuffer(metrics))
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to create http.Request: %w", err)
|
||||
}
|
||||
req.Header.Add("Content-Type", "application/json")
|
||||
req.Header.Set("Content-Encoding", "gzip")
|
||||
|
||||
resp, err := l.client.Do(req)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error POSTing metrics: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode < 200 || resp.StatusCode > 209 {
|
||||
return fmt.Errorf("received bad status code, %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *Logzio) authURL() (string, error) {
|
||||
token, err := l.Token.Get()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("getting token failed: %w", err)
|
||||
}
|
||||
defer token.Destroy()
|
||||
|
||||
return fmt.Sprintf("%s/?token=%s", l.URL, token.TemporaryString()), nil
|
||||
}
|
||||
|
||||
func parseMetric(metric telegraf.Metric) *Metric {
|
||||
return &Metric{
|
||||
Metric: map[string]interface{}{
|
||||
metric.Name(): metric.Fields(),
|
||||
},
|
||||
Dimensions: metric.Tags(),
|
||||
Time: metric.Time(),
|
||||
Type: logzioType,
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
outputs.Add("logzio", func() telegraf.Output {
|
||||
return &Logzio{
|
||||
URL: defaultLogzioURL,
|
||||
Timeout: config.Duration(time.Second * 5),
|
||||
}
|
||||
})
|
||||
}
|
135
plugins/outputs/logzio/logzio_test.go
Normal file
135
plugins/outputs/logzio/logzio_test.go
Normal file
|
@ -0,0 +1,135 @@
|
|||
package logzio
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/influxdata/telegraf"
|
||||
"github.com/influxdata/telegraf/config"
|
||||
"github.com/influxdata/telegraf/testutil"
|
||||
)
|
||||
|
||||
const (
|
||||
testToken = "123456789"
|
||||
testURL = "https://logzio.com"
|
||||
)
|
||||
|
||||
func TestConnectWithoutToken(t *testing.T) {
|
||||
l := &Logzio{
|
||||
URL: testURL,
|
||||
Log: testutil.Logger{},
|
||||
}
|
||||
err := l.Connect()
|
||||
require.ErrorContains(t, err, "token is required")
|
||||
}
|
||||
|
||||
func TestConnectWithDefaultToken(t *testing.T) {
|
||||
l := &Logzio{
|
||||
URL: testURL,
|
||||
Token: config.NewSecret([]byte("your logz.io token")),
|
||||
Log: testutil.Logger{},
|
||||
}
|
||||
err := l.Connect()
|
||||
require.ErrorContains(t, err, "please replace 'token'")
|
||||
}
|
||||
|
||||
func TestParseMetric(t *testing.T) {
|
||||
for _, tm := range testutil.MockMetrics() {
|
||||
lm := parseMetric(tm)
|
||||
require.Equal(t, tm.Fields(), lm.Metric[tm.Name()])
|
||||
require.Equal(t, logzioType, lm.Type)
|
||||
require.Equal(t, tm.Tags(), lm.Dimensions)
|
||||
require.Equal(t, tm.Time(), lm.Time)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBadStatusCode(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
l := &Logzio{
|
||||
Token: config.NewSecret([]byte(testToken)),
|
||||
URL: ts.URL,
|
||||
Log: testutil.Logger{},
|
||||
}
|
||||
require.NoError(t, l.Connect())
|
||||
require.Error(t, l.Write(testutil.MockMetrics()))
|
||||
}
|
||||
|
||||
func TestWrite(t *testing.T) {
|
||||
tm := testutil.TestMetric(float64(3.14), "test1")
|
||||
var body bytes.Buffer
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
gz, err := gzip.NewReader(r.Body)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
var maxDecompressionSize int64 = 500 * 1024 * 1024
|
||||
n, err := io.CopyN(&body, gz, maxDecompressionSize)
|
||||
if errors.Is(err, io.EOF) {
|
||||
err = nil
|
||||
}
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
if n > maxDecompressionSize {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
t.Errorf("Size of decoded data exceeds (%v) allowed size (%v)", n, maxDecompressionSize)
|
||||
return
|
||||
}
|
||||
|
||||
var lm Metric
|
||||
if err = json.Unmarshal(body.Bytes(), &lm); err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(lm.Metric[tm.Name()], tm.Fields()) {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
t.Errorf("Not equal, expected: %q, actual: %q", tm.Fields(), lm.Metric[tm.Name()])
|
||||
return
|
||||
}
|
||||
if lm.Type != logzioType {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
t.Errorf("Not equal, expected: %q, actual: %q", logzioType, lm.Type)
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(lm.Dimensions, tm.Tags()) {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
t.Errorf("Not equal, expected: %q, actual: %q", tm.Tags(), lm.Dimensions)
|
||||
return
|
||||
}
|
||||
if lm.Time != tm.Time() {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
t.Errorf("Not equal, expected: %q, actual: %q", tm.Time(), lm.Time)
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
l := &Logzio{
|
||||
Token: config.NewSecret([]byte(testToken)),
|
||||
URL: ts.URL,
|
||||
Log: testutil.Logger{},
|
||||
}
|
||||
require.NoError(t, l.Connect())
|
||||
require.NoError(t, l.Write([]telegraf.Metric{tm}))
|
||||
}
|
15
plugins/outputs/logzio/sample.conf
Normal file
15
plugins/outputs/logzio/sample.conf
Normal file
|
@ -0,0 +1,15 @@
|
|||
# A plugin that can send metrics over HTTPs to Logz.io
|
||||
[[outputs.logzio]]
|
||||
## Connection timeout, defaults to "5s" if not set.
|
||||
# timeout = "5s"
|
||||
|
||||
## Optional TLS Config
|
||||
# tls_ca = "/etc/telegraf/ca.pem"
|
||||
# tls_cert = "/etc/telegraf/cert.pem"
|
||||
# tls_key = "/etc/telegraf/key.pem"
|
||||
|
||||
## Logz.io account token
|
||||
token = "your logz.io token" # required
|
||||
|
||||
## Use your listener URL for your Logz.io account region.
|
||||
# url = "https://listener.logz.io:8071"
|
Loading…
Add table
Add a link
Reference in a new issue