Skip to content

Commit

Permalink
Add metadata to User-Agent header (#5774)
Browse files Browse the repository at this point in the history
* extract widely duplicated user agent code into shared package

* add useragent package

* space

* add goos and operator flag

* set AGENT_OPERATOR env var

* add space

* move to internal

* switch to deploy mode env

* switch to deploy mode env

* add deploy mode to helm chart

* add deploy mode to deb and rpm

* add deploy mode to docker image

* tests

* regen helm

* use binary as fallback deploy mode

* fix test

* changelog
  • Loading branch information
captncraig authored Nov 15, 2023
1 parent 36d4dec commit ea7b005
Show file tree
Hide file tree
Showing 46 changed files with 252 additions and 33 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,8 @@ Main (unreleased)

- Use Go 1.21.4 for builds. (@rfratto)

- Change User-Agent header for outbound requests to include agent-mode, goos, and deployment mode. Example `GrafanaAgent/v0.38.0 (flow; linux; docker)` (@captncraig)

v0.37.4 (2023-11-06)
-----------------

Expand Down
1 change: 1 addition & 0 deletions cmd/grafana-agent/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,5 @@ COPY cmd/grafana-agent/agent-local-config.yaml /etc/agent/agent.yaml


ENTRYPOINT ["/bin/grafana-agent"]
ENV AGENT_DEPLOY_MODE=docker
CMD ["--config.file=/etc/agent/agent.yaml", "--metrics.wal-directory=/etc/agent/data"]
4 changes: 2 additions & 2 deletions component/common/kubernetes/kubernetes.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (

"github.com/go-kit/log"
commoncfg "github.com/grafana/agent/component/common/config"
"github.com/grafana/agent/pkg/build"
"github.com/grafana/agent/internal/useragent"
"github.com/grafana/agent/pkg/flow/logging/level"
promconfig "github.com/prometheus/common/config"
"k8s.io/client-go/rest"
Expand Down Expand Up @@ -79,7 +79,7 @@ func (args *ClientArguments) BuildRESTConfig(l log.Logger) (*rest.Config, error)
}
}

cfg.UserAgent = fmt.Sprintf("GrafanaAgent/%s", build.Version)
cfg.UserAgent = useragent.Get()
cfg.ContentType = "application/vnd.kubernetes.protobuf"

return cfg, nil
Expand Down
6 changes: 3 additions & 3 deletions component/common/loki/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@ import (
"time"

"github.com/go-kit/log"
"github.com/grafana/agent/internal/useragent"
"github.com/grafana/agent/pkg/flow/logging/level"
"github.com/grafana/dskit/backoff"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/common/config"
"github.com/prometheus/common/model"

"github.com/grafana/agent/component/common/loki"
"github.com/grafana/agent/pkg/build"
"github.com/grafana/agent/pkg/util"
lokiutil "github.com/grafana/loki/pkg/util"
)
Expand All @@ -47,7 +47,7 @@ const (

var Reasons = []string{ReasonGeneric, ReasonRateLimited, ReasonStreamLimited, ReasonLineTooLong}

var UserAgent = fmt.Sprintf("GrafanaAgent/%s", build.Version)
var userAgent = useragent.Get()

type Metrics struct {
encodedBytes *prometheus.CounterVec
Expand Down Expand Up @@ -419,7 +419,7 @@ func (c *client) send(ctx context.Context, tenantID string, buf []byte) (int, er
}
req = req.WithContext(ctx)
req.Header.Set("Content-Type", contentType)
req.Header.Set("User-Agent", UserAgent)
req.Header.Set("User-Agent", userAgent)

// If the tenant ID is not empty promtail is running in multi-tenant mode, so
// we should send it to Loki
Expand Down
2 changes: 1 addition & 1 deletion component/common/loki/client/queue_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,7 @@ func (c *queueClient) send(ctx context.Context, tenantID string, buf []byte) (in
}
req = req.WithContext(ctx)
req.Header.Set("Content-Type", contentType)
req.Header.Set("User-Agent", UserAgent)
req.Header.Set("User-Agent", userAgent)

// If the tenant ID is not empty promtail is running in multi-tenant mode, so
// we should send it to Loki
Expand Down
4 changes: 2 additions & 2 deletions component/loki/source/docker/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import (
flow_relabel "github.com/grafana/agent/component/common/relabel"
"github.com/grafana/agent/component/discovery"
dt "github.com/grafana/agent/component/loki/source/docker/internal/dockertarget"
"github.com/grafana/agent/pkg/build"
"github.com/grafana/agent/internal/useragent"
"github.com/grafana/agent/pkg/flow/logging/level"
"github.com/prometheus/common/config"
"github.com/prometheus/common/model"
Expand All @@ -40,7 +40,7 @@ func init() {
})
}

var userAgent = fmt.Sprintf("GrafanaAgent/%s", build.Version)
var userAgent = useragent.Get()

const (
dockerLabel = model.MetaLabelPrefix + "docker_"
Expand Down
3 changes: 0 additions & 3 deletions component/loki/write/write.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import (
"github.com/grafana/agent/component/common/loki/client"
"github.com/grafana/agent/component/common/loki/limit"
"github.com/grafana/agent/component/common/loki/wal"
"github.com/grafana/agent/pkg/build"
)

func init() {
Expand All @@ -25,8 +24,6 @@ func init() {
return New(opts, args.(Arguments))
},
})

client.UserAgent = fmt.Sprintf("GrafanaAgent/%s", build.Version)
}

// Arguments holds values which are used to configure the loki.write component.
Expand Down
4 changes: 2 additions & 2 deletions component/prometheus/remotewrite/remote_write.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import (

"github.com/go-kit/log"
"github.com/grafana/agent/component"
"github.com/grafana/agent/pkg/build"
"github.com/grafana/agent/internal/useragent"
"github.com/grafana/agent/pkg/flow/logging/level"
"github.com/grafana/agent/pkg/metrics/wal"
"github.com/prometheus/prometheus/model/timestamp"
Expand All @@ -35,7 +35,7 @@ import (
var remoteFlushDeadline = 1 * time.Minute

func init() {
remote.UserAgent = fmt.Sprintf("GrafanaAgent/%s", build.Version)
remote.UserAgent = useragent.Get()

component.Register(component.Registration{
Name: "prometheus.remote_write",
Expand Down
4 changes: 2 additions & 2 deletions component/prometheus/scrape/scrape.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
component_config "github.com/grafana/agent/component/common/config"
"github.com/grafana/agent/component/discovery"
"github.com/grafana/agent/component/prometheus"
"github.com/grafana/agent/pkg/build"
"github.com/grafana/agent/internal/useragent"
"github.com/grafana/agent/pkg/flow/logging/level"
"github.com/grafana/agent/service/cluster"
"github.com/grafana/agent/service/http"
Expand All @@ -27,7 +27,7 @@ import (
)

func init() {
scrape.UserAgent = fmt.Sprintf("GrafanaAgent/%s", build.Version)
scrape.UserAgent = useragent.Get()

component.Register(component.Registration{
Name: "prometheus.scrape",
Expand Down
5 changes: 2 additions & 3 deletions component/pyroscope/scrape/scrape_loop.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,17 @@ import (

"github.com/go-kit/log"
"github.com/grafana/agent/component/pyroscope"
"github.com/grafana/agent/internal/useragent"
"github.com/grafana/agent/pkg/flow/logging/level"
commonconfig "github.com/prometheus/common/config"
"github.com/prometheus/prometheus/discovery/targetgroup"
"github.com/prometheus/prometheus/util/pool"
"golang.org/x/net/context/ctxhttp"

"github.com/grafana/agent/pkg/build"
)

var (
payloadBuffers = pool.New(1e3, 1e6, 3, func(sz int) interface{} { return make([]byte, 0, sz) })
userAgentHeader = fmt.Sprintf("GrafanaAgent/%s", build.Version)
userAgentHeader = useragent.Get()
)

type scrapePool struct {
Expand Down
5 changes: 2 additions & 3 deletions component/pyroscope/write/write.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ package write
import (
"context"
"errors"
"fmt"
"strings"
"time"

"github.com/bufbuild/connect-go"
"github.com/grafana/agent/component/pyroscope"
"github.com/grafana/agent/internal/useragent"
"github.com/grafana/agent/pkg/flow/logging/level"
"github.com/oklog/run"
commonconfig "github.com/prometheus/common/config"
Expand All @@ -18,15 +18,14 @@ import (

"github.com/grafana/agent/component"
"github.com/grafana/agent/component/common/config"
"github.com/grafana/agent/pkg/build"
"github.com/grafana/dskit/backoff"
pushv1 "github.com/grafana/pyroscope/api/gen/proto/go/push/v1"
"github.com/grafana/pyroscope/api/gen/proto/go/push/v1/pushv1connect"
typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1"
)

var (
userAgent = fmt.Sprintf("GrafanaAgent/%s", build.Version)
userAgent = useragent.Get()
DefaultArguments = func() Arguments {
return Arguments{}
}
Expand Down
4 changes: 2 additions & 2 deletions component/remote/http/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ import (
"github.com/go-kit/log"
"github.com/grafana/agent/component"
common_config "github.com/grafana/agent/component/common/config"
"github.com/grafana/agent/pkg/build"
"github.com/grafana/agent/internal/useragent"
"github.com/grafana/agent/pkg/flow/logging/level"
"github.com/grafana/river/rivertypes"
prom_config "github.com/prometheus/common/config"
)

var userAgent = fmt.Sprintf("GrafanaAgent/%s", build.Version)
var userAgent = useragent.Get()

func init() {
component.Register(component.Registration{
Expand Down
60 changes: 60 additions & 0 deletions internal/useragent/useragent.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// package useragent provides a consistent way to get a user agent for outbound http requests from Grafana Agent.
// The default User-Agent is `GrafanaAgent/$VERSION($MODE)`
// Where version is the build version of the agent and MODE is one of "static" or "flow".
package useragent

import (
"fmt"
"os"
"runtime"
"strings"

"github.com/grafana/agent/pkg/build"
)

const (
deployModeEnv = "AGENT_DEPLOY_MODE"
modeEnv = "AGENT_MODE"
)

// settable by tests
var goos = runtime.GOOS

func Get() string {
parenthesis := ""
metadata := []string{}
if mode := getRunMode(); mode != "" {
metadata = append(metadata, mode)
}
metadata = append(metadata, goos)
if op := getDeployMode(); op != "" {
metadata = append(metadata, op)
}
if len(metadata) > 0 {
parenthesis = fmt.Sprintf(" (%s)", strings.Join(metadata, "; "))
}
return fmt.Sprintf("GrafanaAgent/%s%s", build.Version, parenthesis)
}

// getRunMode attempts to get agent mode, using `unknown` for invalid values.
func getRunMode() string {
key := os.Getenv(modeEnv)
switch key {
case "flow":
return "flow"
case "static", "":
return "static"
default:
return "unknown"
}
}

func getDeployMode() string {
op := os.Getenv(deployModeEnv)
// only return known modes. Use "binary" as a default catch-all.
switch op {
case "operator", "helm", "docker", "deb", "rpm", "brew":
return op
}
return "binary"
}
89 changes: 89 additions & 0 deletions internal/useragent/useragent_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package useragent

import (
"testing"

"github.com/grafana/agent/pkg/build"
"github.com/stretchr/testify/require"
)

func TestUserAgent(t *testing.T) {
build.Version = "v1.2.3"
tests := []struct {
Name string
Mode string
Expected string
DeployMode string
GOOS string
}{
{
Name: "basic",
Mode: "",
Expected: "GrafanaAgent/v1.2.3 (static; linux; binary)",
GOOS: "linux",
},
{
Name: "flow",
Mode: "flow",
Expected: "GrafanaAgent/v1.2.3 (flow; windows; binary)",
GOOS: "windows",
},
{
Name: "static",
Mode: "static",
Expected: "GrafanaAgent/v1.2.3 (static; darwin; binary)",
GOOS: "darwin",
},
{
Name: "unknown",
Mode: "blahlahblah",
// unknown mode, should not happen. But we will substitute 'unknown' to avoid allowing arbitrary cardinality.
Expected: "GrafanaAgent/v1.2.3 (unknown; freebsd; binary)",
GOOS: "freebsd",
},
{
Name: "operator",
Mode: "static",
DeployMode: "operator",
Expected: "GrafanaAgent/v1.2.3 (static; linux; operator)",
GOOS: "linux",
},
{
Name: "deb",
Mode: "flow",
DeployMode: "deb",
Expected: "GrafanaAgent/v1.2.3 (flow; linux; deb)",
GOOS: "linux",
},
{
Name: "rpm",
Mode: "static",
DeployMode: "rpm",
Expected: "GrafanaAgent/v1.2.3 (static; linux; rpm)",
GOOS: "linux",
},
{
Name: "docker",
Mode: "flow",
DeployMode: "docker",
Expected: "GrafanaAgent/v1.2.3 (flow; linux; docker)",
GOOS: "linux",
},
{
Name: "helm",
Mode: "flow",
DeployMode: "helm",
Expected: "GrafanaAgent/v1.2.3 (flow; linux; helm)",
GOOS: "linux",
},
}
for _, tst := range tests {
t.Run(tst.Name, func(t *testing.T) {
goos = tst.GOOS
t.Setenv(deployModeEnv, tst.DeployMode)
t.Setenv(modeEnv, tst.Mode)
actual := Get()
require.Equal(t, tst.Expected, actual)
})
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
env:
- name: AGENT_MODE
value: {{ .Values.agent.mode }}
- name: AGENT_DEPLOY_MODE
value: "helm"
- name: HOSTNAME
valueFrom:
fieldRef:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ spec:
env:
- name: AGENT_MODE
value: flow
- name: AGENT_DEPLOY_MODE
value: "helm"
- name: HOSTNAME
valueFrom:
fieldRef:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ spec:
env:
- name: AGENT_MODE
value: flow
- name: AGENT_DEPLOY_MODE
value: "helm"
- name: HOSTNAME
valueFrom:
fieldRef:
Expand Down
Loading

0 comments on commit ea7b005

Please sign in to comment.