Skip to content

Commit bb9ac34

Browse files
authored
feat: relay to phlare (#21)
add PYROSCOPE_SCOPE_ORGID for phlare multitenancy add PYROSCOPE_HTTP_HEADERS just in case join ingestion path url so if the extension is configured with https://foo:4242/bar/ it will be ingested to https://foo:4242/bar/ingest use basic auth from PYROSCOPE_REMOTE_ADDRESS use basic auth from PYROSCOPE_BASIC_AUTH_USER PYROSCOPE_BASIC_AUTH_PASSWORD
1 parent 8b4aa5b commit bb9ac34

File tree

5 files changed

+61
-31
lines changed

5 files changed

+61
-31
lines changed

README.md

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,19 @@ If needed, the `PYROSCOPE_AUTH_TOKEN` can be supplied.
2323
For a complete list of variables check the section below.
2424

2525
## Configuration
26-
| env var | default | description |
27-
|------------------------------|----------------------------------|---------------------------------------------------------------------------------|
28-
| `PYROSCOPE_REMOTE_ADDRESS` | `https://ingest.pyroscope.cloud` | the pyroscope instance data will be relayed to |
29-
| `PYROSCOPE_AUTH_TOKEN` | `""` | authorization key (token authentication) |
30-
| `PYROSCOPE_SELF_PROFILING` | `false` | whether to profile the extension itself or not |
31-
| `PYROSCOPE_LOG_LEVEL` | `info` | `error` or `info` or `debug` or `trace` |
32-
| `PYROSCOPE_TIMEOUT` | `10s` | http client timeout ([go duration format](https://pkg.go.dev/time#Duration)) |
33-
| `PYROSCOPE_NUM_WORKERS` | `5` | num of relay workers, pick based on the number of profile types |
34-
| `PYROSCOPE_FLUSH_ON_INVOKE` | `false` | wait for all relay requests to be finished/flushed before next `Invocation` event is allowed |
26+
| env var | default | description |
27+
|-----------------------------|----------------------------------|----------------------------------------------------------------------------------------------|
28+
| `PYROSCOPE_REMOTE_ADDRESS` | `https://ingest.pyroscope.cloud` | the pyroscope instance data will be relayed to |
29+
| `PYROSCOPE_AUTH_TOKEN` | `""` | authorization key (token authentication) |
30+
| `PYROSCOPE_SELF_PROFILING` | `false` | whether to profile the extension itself or not |
31+
| `PYROSCOPE_LOG_LEVEL` | `info` | `error` or `info` or `debug` or `trace` |
32+
| `PYROSCOPE_TIMEOUT` | `10s` | http client timeout ([go duration format](https://pkg.go.dev/time#Duration)) |
33+
| `PYROSCOPE_NUM_WORKERS` | `5` | num of relay workers, pick based on the number of profile types |
34+
| `PYROSCOPE_FLUSH_ON_INVOKE` | `false` | wait for all relay requests to be finished/flushed before next `Invocation` event is allowed |
35+
| `PYROSCOPE_HTTP_HEADERS` | `{}` | extra http headers in json format, for example: {"X-Header": "Value"} |
36+
| `PYROSCOPE_SCOPE_ORGID` | `""` | phlare tenant ID, passed as X-Scope-OrgID http header |
37+
| `PYROSCOPE_BASIC_AUTH_USER` | `""` | HTTP basic auth user |
38+
| `PYROSCOPE_BASIC_AUTH_PASSWORD` | `""` | HTTP basic auth password |
3539

3640
# How it works
3741
The profiler will run as normal, and periodically will send data to the relay server (the server running at `http://localhost:4040`).

go.mod

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,35 +4,33 @@ go 1.18
44

55
require (
66
github.com/aws/aws-lambda-go v1.32.0
7-
github.com/pyroscope-io/client v0.2.4-0.20220607180407-0ba26860ce5b
7+
github.com/davecgh/go-spew v1.1.1
8+
github.com/mgechev/revive v1.2.1
9+
github.com/pyroscope-io/client v0.7.0
810
github.com/sirupsen/logrus v1.8.1
911
github.com/stretchr/testify v1.7.4
1012
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
11-
gotest.tools v2.2.0+incompatible
13+
honnef.co/go/tools v0.3.2
1214
)
1315

1416
require (
1517
github.com/BurntSushi/toml v1.1.0 // indirect
1618
github.com/chavacava/garif v0.0.0-20220316182200-5cad0b5181d4 // indirect
17-
github.com/davecgh/go-spew v1.1.1 // indirect
1819
github.com/fatih/color v1.13.0 // indirect
1920
github.com/fatih/structtag v1.2.0 // indirect
20-
github.com/google/go-cmp v0.5.7 // indirect
2121
github.com/mattn/go-colorable v0.1.9 // indirect
2222
github.com/mattn/go-isatty v0.0.14 // indirect
2323
github.com/mattn/go-runewidth v0.0.9 // indirect
2424
github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517 // indirect
25-
github.com/mgechev/revive v1.2.1 // indirect
2625
github.com/mitchellh/go-homedir v1.1.0 // indirect
2726
github.com/olekukonko/tablewriter v0.0.5 // indirect
2827
github.com/pkg/errors v0.9.1 // indirect
2928
github.com/pmezard/go-difflib v1.0.0 // indirect
29+
github.com/pyroscope-io/godeltaprof v0.1.0 // indirect
3030
golang.org/x/exp/typeparams v0.0.0-20220218215828-6cf2b201936e // indirect
3131
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
3232
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect
3333
golang.org/x/tools v0.1.11-0.20220513221640-090b14e8501f // indirect
34-
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
3534
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
3635
gopkg.in/yaml.v3 v3.0.1 // indirect
37-
honnef.co/go/tools v0.3.2 // indirect
3836
)

go.sum

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
1111
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
1212
github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
1313
github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
14-
github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=
15-
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
1614
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
1715
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
1816
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
@@ -37,8 +35,10 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
3735
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
3836
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
3937
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
40-
github.com/pyroscope-io/client v0.2.4-0.20220607180407-0ba26860ce5b h1:5YuLgMAQ7XbW8Kmccwv0C1vkl85SG7ItLC8AdMtCFOs=
41-
github.com/pyroscope-io/client v0.2.4-0.20220607180407-0ba26860ce5b/go.mod h1:zRdQXIGxy0H2QbKEkCmZBR6KOLLIFYLWsdzVI0MRm2E=
38+
github.com/pyroscope-io/client v0.7.0 h1:LWuuqPQ1oa6x7BnmUOuo/aGwdX85QGhWZUBYWWW3zdk=
39+
github.com/pyroscope-io/client v0.7.0/go.mod h1:4h21iOU4pUOq0prKyDlvYRL+SCKsBc5wKiEtV+rJGqU=
40+
github.com/pyroscope-io/godeltaprof v0.1.0 h1:UBqtjt0yZi4jTxqZmLAs34XG6ycS3vUTlhEUSq4NHLE=
41+
github.com/pyroscope-io/godeltaprof v0.1.0/go.mod h1:psMITXp90+8pFenXkKIpNhrfmI9saQnPbba27VIaiQE=
4242
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
4343
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
4444
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@@ -79,22 +79,17 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
7979
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
8080
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
8181
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
82-
golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20=
8382
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
8483
golang.org/x/tools v0.1.11-0.20220513221640-090b14e8501f h1:OKYpQQVE3DKSc3r3zHVzq46vq5YH7x8xpR3/k9ixmUg=
8584
golang.org/x/tools v0.1.11-0.20220513221640-090b14e8501f/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4=
8685
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
8786
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
88-
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
89-
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
9087
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
9188
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
9289
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
9390
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
9491
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
9592
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
9693
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
97-
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
98-
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
9994
honnef.co/go/tools v0.3.2 h1:ytYb4rOqyp1TSa2EPvNVwtPQJctSELKaMyLfqNP4+34=
10095
honnef.co/go/tools v0.3.2/go.mod h1:jzwdWgg7Jdq75wlfblQxO4neNaFFSvgc1tD5Wv8U0Yw=

main.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,19 @@ var (
3131
// to where relay data to
3232
remoteAddress = getEnvStrOr("PYROSCOPE_REMOTE_ADDRESS", "https://ingest.pyroscope.cloud")
3333

34-
authToken = getEnvStrOr("PYROSCOPE_AUTH_TOKEN", "")
35-
timeout = getEnvDurationOr("PYROSCOPE_TIMEOUT", time.Second*10)
36-
numWorkers = getEnvIntOr("PYROSCOPE_NUM_WORKERS", 5)
34+
authToken = getEnvStrOr("PYROSCOPE_AUTH_TOKEN", "")
35+
basicAuthUser = getEnvStrOr("PYROSCOPE_BASIC_AUTH_USER", "")
36+
basicAuthPassword = getEnvStrOr("PYROSCOPE_BASIC_AUTH_PASSWORD", "")
37+
scopeOrgID = getEnvStrOr("PYROSCOPE_SCOPE_ORGID", "")
38+
timeout = getEnvDurationOr("PYROSCOPE_TIMEOUT", time.Second*10)
39+
numWorkers = getEnvIntOr("PYROSCOPE_NUM_WORKERS", 5)
3740

3841
// profile the extension?
3942
selfProfiling = getEnvBool("PYROSCOPE_SELF_PROFILING")
4043

4144
flushOnInvoke = getEnvBool("PYROSCOPE_FLUSH_ON_INVOKE")
45+
46+
httpHeaders = getEnvStrOr("PYROSCOPE_HTTP_HEADERS", "")
4247
)
4348

4449
func main() {
@@ -49,6 +54,10 @@ func main() {
4954
remoteClient := relay.NewRemoteClient(logger, &relay.RemoteClientCfg{
5055
Address: remoteAddress,
5156
AuthToken: authToken,
57+
BasicAuthUser: basicAuthUser,
58+
BasicAuthPassword: basicAuthPassword,
59+
ScopeOrgID: scopeOrgID,
60+
HTTPHeadersJSON: httpHeaders,
5261
Timeout: timeout,
5362
MaxIdleConnsPerHost: numWorkers,
5463
})

relay/client.go

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package relay
22

33
import (
4+
"encoding/json"
45
"errors"
56
"fmt"
67
"io/ioutil"
78
"net/http"
89
"net/url"
10+
"path"
911
"time"
1012

1113
"github.com/sirupsen/logrus"
@@ -20,14 +22,19 @@ type RemoteClientCfg struct {
2022
// Address refers to the remote address the request will be made to
2123
Address string
2224
AuthToken string
25+
BasicAuthUser string
26+
BasicAuthPassword string
27+
ScopeOrgID string
28+
HTTPHeadersJSON string
2329
Timeout time.Duration
2430
MaxIdleConnsPerHost int
2531
}
2632

2733
type RemoteClient struct {
28-
config *RemoteClientCfg
29-
client *http.Client
30-
log *logrus.Entry
34+
config *RemoteClientCfg
35+
client *http.Client
36+
headers map[string]string
37+
log *logrus.Entry
3138
}
3239

3340
func NewRemoteClient(log *logrus.Entry, config *RemoteClientCfg) *RemoteClient {
@@ -38,6 +45,13 @@ func NewRemoteClient(log *logrus.Entry, config *RemoteClientCfg) *RemoteClient {
3845
if config.MaxIdleConnsPerHost == 0 {
3946
config.MaxIdleConnsPerHost = 5
4047
}
48+
headers := make(map[string]string)
49+
if config.HTTPHeadersJSON != "" {
50+
err := json.Unmarshal([]byte(config.HTTPHeadersJSON), &headers)
51+
if err != nil {
52+
log.Error(fmt.Errorf("failed to parse headers json %w", err))
53+
}
54+
}
4155
return &RemoteClient{
4256
log: log,
4357
config: config,
@@ -56,6 +70,12 @@ func (r *RemoteClient) Send(req *http.Request) error {
5670
defer req.Body.Close()
5771
}
5872
r.enhanceWithAuthToken(req)
73+
if r.config.ScopeOrgID != "" {
74+
req.Header.Set("X-Scope-OrgID", r.config.ScopeOrgID)
75+
}
76+
for k, v := range r.headers {
77+
req.Header.Set(k, v)
78+
}
5979

6080
host := r.config.Address
6181

@@ -64,6 +84,8 @@ func (r *RemoteClient) Send(req *http.Request) error {
6484
req.RequestURI = ""
6585
req.URL.Host = u.Host
6686
req.URL.Scheme = u.Scheme
87+
req.URL.User = u.User
88+
req.URL.Path = path.Join(u.Path, req.URL.Path)
6789
req.Header.Set("X-Forwarded-Host", req.Header.Get("Host"))
6890
req.Host = u.Host
6991

@@ -91,5 +113,7 @@ func (r *RemoteClient) enhanceWithAuthToken(req *http.Request) {
91113

92114
if token != "" {
93115
req.Header.Set("Authorization", "Bearer "+token)
116+
} else if r.config.BasicAuthUser != "" && r.config.BasicAuthPassword != "" {
117+
req.SetBasicAuth(r.config.BasicAuthUser, r.config.BasicAuthPassword)
94118
}
95119
}

0 commit comments

Comments
 (0)