Skip to content
This repository was archived by the owner on Nov 2, 2023. It is now read-only.

Commit 51b3652

Browse files
author
Julio Guerra
committed
v1.0.1
- Fix Sqreen's overhead rate calculation when the observed execution time is 0. This situation can happen when the execution timer wasn't precise enough in order to observe fast execution times. - Add a new backend url configuration key `ingestion_url` for validation testing.
2 parents 73d60e7 + 39c8b7b commit 51b3652

File tree

17 files changed

+196
-44
lines changed

17 files changed

+196
-44
lines changed

CHANGELOG.md

+13
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
# v1.0.1 - 16 February 2021
2+
3+
## Fix
4+
5+
- Fix Sqreen's overhead rate calculation when the observed execution time is 0.
6+
This situation can happen when the execution timer wasn't precise enough in
7+
order to observe fast execution times.
8+
9+
## Internal Changes
10+
11+
- Add a new backend url configuration key `ingestion_url` for validation
12+
testing.
13+
114
# v1.0.0 - 19 November 2020
215

316
## New Features

examples/docker/alpine/Dockerfile

+4
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ FROM golang:$GO_VERSION AS build
88
WORKDIR /app
99
COPY . .
1010

11+
# Update the go.mod and go.sum dependencies
12+
RUN go get -d github.com/sqreen/go-agent/sdk/sqreen-instrumentation-tool
13+
RUN go get -d ./...
14+
1115
# Install Sqreen's instrumentation tool.
1216
# Go modules make it easier by correctly choosing the version of your go.mod.
1317
RUN go build -v github.com/sqreen/go-agent/sdk/sqreen-instrumentation-tool

examples/docker/debian/Dockerfile

+4-1
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,11 @@ FROM golang:$GO_VERSION AS build
88
WORKDIR /app
99
COPY . .
1010

11+
# Update the go.mod and go.sum dependencies
12+
RUN go get -d github.com/sqreen/go-agent/sdk/sqreen-instrumentation-tool
13+
RUN go get -d ./...
14+
1115
# Install Sqreen's instrumentation tool.
12-
# Go modules make it easier by correctly choosing the version of your go.mod.
1316
RUN go build -v github.com/sqreen/go-agent/sdk/sqreen-instrumentation-tool
1417

1518
# Compile the app with the previously built tool.

examples/docker/scratch/Dockerfile

+4
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ FROM golang:$GO_VERSION AS build
99
WORKDIR /app
1010
COPY . .
1111

12+
# Update the go.mod and go.sum dependencies
13+
RUN go get -d github.com/sqreen/go-agent/sdk/sqreen-instrumentation-tool
14+
RUN go get -d ./...
15+
1216
# Install Sqreen's instrumentation tool.
1317
# Go modules make it easier by correctly choosing the version of your go.mod.
1418
RUN go build -v github.com/sqreen/go-agent/sdk/sqreen-instrumentation-tool

go.mod

+2-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ require (
2222
github.com/mattn/go-colorable v0.1.8 // indirect
2323
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
2424
github.com/modern-go/reflect2 v1.0.1 // indirect
25-
github.com/mxschmitt/golang-combinations v1.1.0
2625
github.com/onsi/ginkgo v1.7.0
2726
github.com/onsi/gomega v1.4.3
2827
github.com/pkg/errors v0.9.1
@@ -31,6 +30,7 @@ require (
3130
github.com/spf13/viper v1.3.2
3231
github.com/sqreen/go-libsqreen v0.7.1
3332
github.com/sqreen/go-sdk/signal v1.2.0
33+
github.com/stretchr/objx v0.3.0 // indirect
3434
github.com/stretchr/testify v1.6.1
3535
go.elastic.co/apm/module/apmsql v1.9.0
3636
golang.org/x/crypto v0.0.0-20201116153603-4be66e5b6582 // indirect
@@ -42,4 +42,5 @@ require (
4242
gopkg.in/go-playground/assert.v1 v1.2.1
4343
gopkg.in/go-playground/validator.v8 v8.18.2 // indirect
4444
gopkg.in/yaml.v2 v2.3.0 // indirect
45+
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
4546
)

go.sum

+4-2
Original file line numberDiff line numberDiff line change
@@ -161,8 +161,6 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ
161161
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
162162
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
163163
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
164-
github.com/mxschmitt/golang-combinations v1.1.0 h1:WlIZCnDm+Xlb2pRPf+R/qPKlGOU1w8lpN69/uy5z+Zg=
165-
github.com/mxschmitt/golang-combinations v1.1.0/go.mod h1:RbMhWvfCelHR6WROvT2bVfxJvZHoEvBj71SKe+H0MYU=
166164
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
167165
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
168166
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
@@ -215,6 +213,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
215213
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
216214
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
217215
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
216+
github.com/stretchr/objx v0.3.0 h1:NGXK3lHquSN08v5vWalVI/L8XU9hdzE/G6xsrze47As=
217+
github.com/stretchr/objx v0.3.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
218218
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
219219
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
220220
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
@@ -360,6 +360,8 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
360360
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
361361
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=
362362
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
363+
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
364+
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
363365
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
364366
howett.net/plist v0.0.0-20181124034731-591f970eefbb h1:jhnBjNi9UFpfpl8YZhA9CrOqpnJdvzuiHsl/dnxl11M=
365367
howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0=

internal/agent.go

+44-14
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import (
1111
"encoding/json"
1212
"fmt"
1313
"io/ioutil"
14+
"math"
15+
"net/url"
1416
"os"
1517
"runtime"
1618
"sync"
@@ -194,7 +196,7 @@ type staticMetrics struct {
194196
allowedIP,
195197
allowedPath,
196198
callCounts *metrics.TimeHistogram
197-
requestTime, sqreenTime, sqreenOverheadPercentage *metrics.PerfHistogram
199+
requestTime, sqreenTime, sqreenOverheadRate *metrics.PerfHistogram
198200
}
199201

200202
// Error channel buffer length.
@@ -256,7 +258,12 @@ func New(cfg *config.Config) *AgentType {
256258
if err != nil {
257259
logger.Error(sqerrors.Wrap(err, "`req` performance histogram constructor error"))
258260
}
259-
sqOverheadPercentage, err := metrics.PerfHistogram("pct", perfHistogramUnit, perfHistogramBase, perfHistogramPeriod)
261+
262+
const (
263+
sqreenOverheadRateBase = 1.3
264+
sqreenOverheadRateUnit = 1.0
265+
)
266+
sqOverheadRate, err := metrics.PerfHistogram("pct", sqreenOverheadRateUnit, sqreenOverheadRateBase, perfHistogramPeriod)
260267
if err != nil {
261268
logger.Error(sqerrors.Wrap(err, "`pct` performance histogram constructor error"))
262269
}
@@ -269,14 +276,14 @@ func New(cfg *config.Config) *AgentType {
269276
isDone: make(chan struct{}),
270277
metrics: metrics,
271278
staticMetrics: staticMetrics{
272-
sdkUserLoginSuccess: metrics.TimeHistogram("sdk-login-success", sdkMetricsPeriod, 60000),
273-
sdkUserLoginFailure: metrics.TimeHistogram("sdk-login-fail", sdkMetricsPeriod, 60000),
274-
sdkUserSignup: metrics.TimeHistogram("sdk-signup", sdkMetricsPeriod, 60000),
275-
allowedIP: metrics.TimeHistogram("whitelisted", sdkMetricsPeriod, 60000),
276-
allowedPath: metrics.TimeHistogram("whitelisted_paths", sdkMetricsPeriod, 60000),
277-
requestTime: req,
278-
sqreenTime: sq,
279-
sqreenOverheadPercentage: sqOverheadPercentage,
279+
sdkUserLoginSuccess: metrics.TimeHistogram("sdk-login-success", sdkMetricsPeriod, 60000),
280+
sdkUserLoginFailure: metrics.TimeHistogram("sdk-login-fail", sdkMetricsPeriod, 60000),
281+
sdkUserSignup: metrics.TimeHistogram("sdk-signup", sdkMetricsPeriod, 60000),
282+
allowedIP: metrics.TimeHistogram("whitelisted", sdkMetricsPeriod, 60000),
283+
allowedPath: metrics.TimeHistogram("whitelisted_paths", sdkMetricsPeriod, 60000),
284+
requestTime: req,
285+
sqreenTime: sq,
286+
sqreenOverheadRate: sqOverheadRate,
280287
},
281288
ctx: ctx,
282289
cancel: cancel,
@@ -322,9 +329,10 @@ func (a *AgentType) sendClosedHTTPProtectionContext(ctx http_protection_types.Cl
322329
a.logger.Error(sqerrors.Wrap(err, "could not add sqreen's execution time"))
323330
}
324331

325-
sqOverhead := 100 * sq / (req - sq)
326-
if err := a.staticMetrics.sqreenOverheadPercentage.Add(sqOverhead); err != nil {
327-
a.logger.Error(sqerrors.Wrap(err, "could not add sqreen's execution time"))
332+
if overheadRate, err := overheadRate(req, sq); err == nil {
333+
if err := a.staticMetrics.sqreenOverheadRate.Add(overheadRate); err != nil {
334+
a.logger.Error(sqerrors.Wrap(err, "could not add sqreen overhead rate"))
335+
}
328336
}
329337

330338
event := newClosedHTTPRequestContextEvent(a.RulespackID(), start, finish, ctx.Response(), ctx.Request(), events)
@@ -334,6 +342,27 @@ func (a *AgentType) sendClosedHTTPProtectionContext(ctx http_protection_types.Cl
334342
a.eventMng.send(event)
335343
}
336344

345+
func overheadRate(req float64, sq float64) (rate float64, err error) {
346+
if req <= 0 || math.IsNaN(req) || math.IsInf(req, 0) {
347+
return 0, sqerrors.Errorf("unexpected req value `%v`", req)
348+
}
349+
if sq <= 0 || math.IsNaN(sq) || math.IsInf(sq, 0) {
350+
return 0, sqerrors.Errorf("unexpected sq value `%v`", sq)
351+
}
352+
if req < sq {
353+
return 0, sqerrors.Errorf("unexpected req `%v` and sq `%v` values: req should be greater or equal to sq", req, sq)
354+
}
355+
if req == sq {
356+
return 100, nil
357+
}
358+
359+
userTime := req - sq
360+
if userTime == 0 {
361+
return 100, nil
362+
}
363+
return 100 * sq / userTime, nil
364+
}
365+
337366
type withNotificationError struct {
338367
error
339368
}
@@ -349,7 +378,8 @@ func (a *AgentType) Serve() error {
349378

350379
token := a.config.BackendHTTPAPIToken()
351380
appName := a.config.AppName()
352-
appLoginRes, err := appLogin(a.ctx, a.logger, a.client, token, appName, a.appInfo, a.config.DisableSignalBackend())
381+
ingestionUrl, _ := url.Parse(a.config.IngestionBackendHTTPAPIBaseURL())
382+
appLoginRes, err := appLogin(a.ctx, a.logger, a.client, token, appName, a.appInfo, a.config.DisableSignalBackend(), ingestionUrl)
353383
if err != nil {
354384
if xerrors.Is(err, context.Canceled) {
355385
a.logger.Debug(err)

internal/agent_test.go

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Copyright (c) 2016 - 2020 Sqreen. All Rights Reserved.
2+
// Please refer to our terms for more information:
3+
// https://www.sqreen.io/terms.html
4+
5+
package internal
6+
7+
import (
8+
"math"
9+
"testing"
10+
11+
"github.com/stretchr/testify/require"
12+
)
13+
14+
func Test_overheadRate(t *testing.T) {
15+
t.Run("no panics nor special float numbers", func(t *testing.T) {
16+
limits := []float64{
17+
math.MaxFloat64,
18+
-math.MaxFloat64,
19+
math.NaN(),
20+
math.Inf(1),
21+
math.Inf(-1),
22+
0,
23+
1,
24+
-1,
25+
-1e100,
26+
1e100,
27+
}
28+
for _, req := range limits {
29+
for _, sq := range limits {
30+
require.NotPanics(t, func() {
31+
rate, _ := overheadRate(req, sq)
32+
require.False(t, math.IsNaN(rate) || math.IsInf(rate, 0))
33+
})
34+
}
35+
}
36+
})
37+
}

internal/backend/api/signal/signal.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -239,14 +239,14 @@ func newAgentExceptionPayload(klass, message string, infos interface{}) *api.Sig
239239
}
240240

241241
func FromLegacyMetrics(metrics []legacy_api.MetricsTimeBucket, agentVersion string, logger plog.ErrorLogger) api.Batch {
242-
batch := make(api.Batch, len(metrics))
243-
for i, metric := range metrics {
242+
batch := make(api.Batch, 0, len(metrics))
243+
for _, metric := range metrics {
244244
metric, err := convertLegacyMetrics(&metric, agentVersion)
245245
if err != nil {
246246
logger.Error(err)
247-
} else {
248-
batch[i] = metric
247+
continue
249248
}
249+
batch = append(batch, metric)
250250
}
251251
return batch
252252
}

internal/backend/client.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ func (c *Client) Health() HealthStatus {
115115
return health
116116
}
117117

118-
func (c *Client) AppLogin(req *api.AppLoginRequest, token string, appName string, disableSignalBackend bool) (*api.AppLoginResponse, error) {
118+
func (c *Client) AppLogin(req *api.AppLoginRequest, token string, appName string, disableSignalBackend bool, defaultIngestionUrl *url.URL) (*api.AppLoginResponse, error) {
119119
httpReq, err := c.newRequest(&config.BackendHTTPAPIEndpoint.AppLogin)
120120
if err != nil {
121121
return nil, err
@@ -138,6 +138,9 @@ func (c *Client) AppLogin(req *api.AppLoginRequest, token string, appName string
138138

139139
if !disableSignalBackend && res.Features.UseSignals {
140140
c.signalClient = client.NewClient(c.client, c.session)
141+
if defaultIngestionUrl != nil {
142+
c.signalClient.BaseURL = defaultIngestionUrl
143+
}
141144

142145
// If the default signal URL is not healthy, fallback to the general
143146
// backend URL.

internal/backend/client_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ func initFakeServerSession(endpointCfg *config.HTTPAPIEndpoint, request, respons
170170

171171
token := testlib.RandHTTPHeaderValue(2, 50)
172172
appName := testlib.RandHTTPHeaderValue(2, 50)
173-
_, err = client.AppLogin(loginReq, token, appName, false)
173+
_, err = client.AppLogin(loginReq, token, appName, false, nil)
174174
if err != nil {
175175
panic(err)
176176
}

internal/client.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"encoding/json"
1313
"fmt"
1414
"net/http"
15+
"net/url"
1516
"time"
1617

1718
"github.com/pkg/errors"
@@ -53,7 +54,7 @@ func (e LoginError) Unwrap() error {
5354

5455
// Login to the backend. When the API request fails, retry for ever and after
5556
// sleeping some time.
56-
func appLogin(ctx context.Context, logger plog.DebugLevelLogger, client *backend.Client, token string, appName string, appInfo *app.Info, disableSignalBackend bool) (*api.AppLoginResponse, error) {
57+
func appLogin(ctx context.Context, logger plog.DebugLevelLogger, client *backend.Client, token string, appName string, appInfo *app.Info, disableSignalBackend bool, defaultIngestionUrl *url.URL) (*api.AppLoginResponse, error) {
5758
_, bundleSignature, err := appInfo.Dependencies()
5859
if err != nil {
5960
logger.Error(withNotificationError{sqerrors.Wrap(err, "could not retrieve the program dependencies")})
@@ -83,7 +84,7 @@ func appLogin(ctx context.Context, logger plog.DebugLevelLogger, client *backend
8384
case <-ctx.Done():
8485
return nil, ctx.Err()
8586
default:
86-
appLoginRes, err = client.AppLogin(&appLoginReq, token, appName, disableSignalBackend)
87+
appLoginRes, err = client.AppLogin(&appLoginReq, token, appName, disableSignalBackend, defaultIngestionUrl)
8788
if err == nil && appLoginRes.Status {
8889
return appLoginRes, nil
8990
}

internal/config/config.go

+25-16
Original file line numberDiff line numberDiff line change
@@ -215,26 +215,29 @@ const (
215215
const (
216216
configEnvKeyConfigFile = `config_file`
217217

218-
configKeyBackendHTTPAPIBaseURL = `url`
219-
configKeyBackendHTTPAPIToken = `token`
220-
configKeyLogLevel = `log_level`
221-
configKeyAppName = `app_name`
222-
configKeyHTTPClientIPHeader = `ip_header`
223-
configKeyHTTPClientIPHeaderFormat = `ip_header_format`
224-
configKeyBackendHTTPAPIProxy = `proxy`
225-
configKeyDisable = `disable`
226-
configKeyStripHTTPReferer = `strip_http_referer`
227-
configKeyRules = `rules`
228-
configKeySDKMetricsPeriod = `sdk_metrics_period`
229-
configKeyMaxMetricsStoreLength = `max_metrics_store_length`
230-
configKeyDisableSignalBackend = `disable_signal_backend`
231-
configKeyStripSensitiveKeyRegexp = `strip_sensitive_key_regexp`
232-
configKeyStripSensitiveValueRegexp = `strip_sensitive_value_regexp`
218+
configKeyBackendHTTPAPIBaseURL = `url`
219+
configKeyIngestionBackendHTTPAPIBaseURL = `ingestion_url`
220+
configKeyBackendHTTPAPIToken = `token`
221+
configKeyLogLevel = `log_level`
222+
configKeyAppName = `app_name`
223+
configKeyHTTPClientIPHeader = `ip_header`
224+
configKeyHTTPClientIPHeaderFormat = `ip_header_format`
225+
configKeyBackendHTTPAPIProxy = `proxy`
226+
configKeyDisable = `disable`
227+
configKeyStripHTTPReferer = `strip_http_referer`
228+
configKeyRules = `rules`
229+
configKeySDKMetricsPeriod = `sdk_metrics_period`
230+
configKeyMaxMetricsStoreLength = `max_metrics_store_length`
231+
configKeyDisableSignalBackend = `disable_signal_backend`
232+
configKeyStripSensitiveKeyRegexp = `strip_sensitive_key_regexp`
233+
configKeyStripSensitiveValueRegexp = `strip_sensitive_value_regexp`
233234
)
234235

235236
// User configuration's default values.
236237
const (
237-
configDefaultBackendHTTPAPIBaseURL = `https://back.sqreen.com`
238+
configDefaultBackendHTTPAPIBaseURL = `https://back.sqreen.com`
239+
configDefaultIngestionBackendHTTPAPIBaseURL = "https://ingestion.sqreen.com/"
240+
238241
configDefaultLogLevel = `info`
239242
configDefaultSDKMetricsPeriod = 60
240243
configDefaultMaxMetricsStoreLength = 100 * 1024 * 1024
@@ -265,6 +268,7 @@ func New(logger *plog.Logger) (*Config, error) {
265268
hidden bool
266269
}{
267270
{key: configKeyBackendHTTPAPIBaseURL, defaultValue: configDefaultBackendHTTPAPIBaseURL},
271+
{key: configKeyIngestionBackendHTTPAPIBaseURL, defaultValue: configDefaultIngestionBackendHTTPAPIBaseURL},
268272
{key: configKeyLogLevel, defaultValue: configDefaultLogLevel},
269273
{key: configKeyBackendHTTPAPIToken, defaultValue: "", secretFromChar: len(BackendHTTPAPIOrganizationTokenSubstr) + 3},
270274
{key: configKeyAppName, defaultValue: ""},
@@ -345,6 +349,11 @@ func (c *Config) BackendHTTPAPIBaseURL() string {
345349
return sanitizeString(c.GetString(configKeyBackendHTTPAPIBaseURL))
346350
}
347351

352+
// IngestionBackendHTTPAPIBaseURL returns the base URL of the backend HTTP API.
353+
func (c *Config) IngestionBackendHTTPAPIBaseURL() string {
354+
return sanitizeString(c.GetString(configKeyIngestionBackendHTTPAPIBaseURL))
355+
}
356+
348357
// BackendHTTPAPIToken returns the access token to the backend API.
349358
func (c *Config) BackendHTTPAPIToken() string {
350359
return sanitizeString(c.GetString(configKeyBackendHTTPAPIToken))

0 commit comments

Comments
 (0)