mirror of
https://github.com/slackhq/nebula.git
synced 2026-08-15 09:57:00 +02:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3cdb94b2a0 |
@@ -73,11 +73,8 @@ jobs:
|
|||||||
build-darwin:
|
build-darwin:
|
||||||
name: Build Universal Darwin
|
name: Build Universal Darwin
|
||||||
env:
|
env:
|
||||||
HAS_SIGNING_CREDS: ${{ secrets.APPLE_SIGNING_ROLE_ARN != '' }}
|
HAS_SIGNING_CREDS: ${{ secrets.AC_USERNAME != '' }}
|
||||||
runs-on: macos-latest
|
runs-on: macos-latest
|
||||||
permissions:
|
|
||||||
id-token: write
|
|
||||||
contents: read
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v7
|
- uses: actions/checkout@v7
|
||||||
|
|
||||||
@@ -86,68 +83,17 @@ jobs:
|
|||||||
go-version: '1.26'
|
go-version: '1.26'
|
||||||
check-latest: true
|
check-latest: true
|
||||||
|
|
||||||
# GitHub holds ARNs, not credentials, and ARNs outlive a rotation
|
|
||||||
- name: Configure AWS credentials
|
|
||||||
if: env.HAS_SIGNING_CREDS == 'true'
|
|
||||||
uses: aws-actions/configure-aws-credentials@v6
|
|
||||||
with:
|
|
||||||
role-to-assume: ${{ secrets.APPLE_SIGNING_ROLE_ARN }}
|
|
||||||
aws-region: us-east-2
|
|
||||||
|
|
||||||
# parse-json-secrets unpacks into SIGNING_* and ASC_*, masked on the way in
|
|
||||||
- name: Fetch signing credentials
|
|
||||||
if: env.HAS_SIGNING_CREDS == 'true'
|
|
||||||
uses: aws-actions/aws-secretsmanager-get-secrets@v3
|
|
||||||
with:
|
|
||||||
parse-json-secrets: true
|
|
||||||
secret-ids: |
|
|
||||||
SIGNING,${{ secrets.APPLE_SIGNING_DEVELOPER_ID_ARN }}
|
|
||||||
ASC,${{ secrets.APPLE_NOTARY_KEY_ARN }}
|
|
||||||
|
|
||||||
- name: Import certificates
|
- name: Import certificates
|
||||||
if: env.HAS_SIGNING_CREDS == 'true'
|
if: env.HAS_SIGNING_CREDS == 'true'
|
||||||
uses: Apple-Actions/import-codesign-certs@v7
|
uses: Apple-Actions/import-codesign-certs@v7
|
||||||
with:
|
with:
|
||||||
p12-file-base64: ${{ env.SIGNING_P12_BASE64 }}
|
p12-file-base64: ${{ secrets.APPLE_DEVELOPER_CERTIFICATE_P12_BASE64 }}
|
||||||
p12-password: ${{ env.SIGNING_PASSWORD }}
|
p12-password: ${{ secrets.APPLE_DEVELOPER_CERTIFICATE_PASSWORD }}
|
||||||
|
|
||||||
# The action imports but does not check the chain validates, which is how a p12
|
|
||||||
# missing its intermediate reaches a failing codesign
|
|
||||||
- name: Check the identity is usable
|
|
||||||
if: env.HAS_SIGNING_CREDS == 'true'
|
|
||||||
run: |
|
|
||||||
: "${SIGNING_IDENTITY_SHA1:?empty, so the secret has no identity_sha1}"
|
|
||||||
identities=$(security find-identity -v -p codesigning signing_temp.keychain)
|
|
||||||
case "$identities" in
|
|
||||||
*"$SIGNING_IDENTITY_SHA1"*) ;;
|
|
||||||
*) printf '%s\n' "$identities" >&2; exit 1 ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# notarytool wants the key as a file
|
|
||||||
- name: Write the App Store Connect key
|
|
||||||
if: env.HAS_SIGNING_CREDS == 'true'
|
|
||||||
run: |
|
|
||||||
mkdir -p ~/private_keys
|
|
||||||
chmod 700 ~/private_keys
|
|
||||||
key_path="$HOME/private_keys/AuthKey_${ASC_KEY_ID}.p8"
|
|
||||||
(umask 077; printf '%s\n' "$ASC_PRIVATE_KEY" > "$key_path")
|
|
||||||
echo "ASC_P8=$key_path" >> "$GITHUB_ENV"
|
|
||||||
|
|
||||||
- name: Drop the credentials from the environment
|
|
||||||
if: env.HAS_SIGNING_CREDS == 'true'
|
|
||||||
run: |
|
|
||||||
# The action's own inventory, so a new field in a secret is covered
|
|
||||||
python3 -c '
|
|
||||||
import json, os
|
|
||||||
raw = os.environ.get("SECRETS_LIST_CLEAN_UP")
|
|
||||||
if raw is None and os.environ.get("SIGNING_P12_BASE64"):
|
|
||||||
raise SystemExit("SECRETS_LIST_CLEAN_UP is gone, fetched secrets are not being scrubbed")
|
|
||||||
keep = {"SIGNING_IDENTITY_SHA1", "ASC_KEY_ID", "ASC_ISSUER_ID"}
|
|
||||||
names = [n for n in json.loads(raw or "[]") if n not in keep]
|
|
||||||
print("\n".join(f"{n}=" for n in dict.fromkeys(names)))
|
|
||||||
' >> "$GITHUB_ENV"
|
|
||||||
|
|
||||||
- name: Build, sign, and notarize
|
- name: Build, sign, and notarize
|
||||||
|
env:
|
||||||
|
AC_USERNAME: ${{ secrets.AC_USERNAME }}
|
||||||
|
AC_PASSWORD: ${{ secrets.AC_PASSWORD }}
|
||||||
run: |
|
run: |
|
||||||
rm -rf release
|
rm -rf release
|
||||||
mkdir release
|
mkdir release
|
||||||
@@ -156,34 +102,17 @@ jobs:
|
|||||||
lipo -create -output ./release/nebula ./build/darwin-amd64/nebula ./build/darwin-arm64/nebula
|
lipo -create -output ./release/nebula ./build/darwin-amd64/nebula ./build/darwin-arm64/nebula
|
||||||
lipo -create -output ./release/nebula-cert ./build/darwin-amd64/nebula-cert ./build/darwin-arm64/nebula-cert
|
lipo -create -output ./release/nebula-cert ./build/darwin-amd64/nebula-cert ./build/darwin-arm64/nebula-cert
|
||||||
|
|
||||||
# Unset in a fork, which has no credentials to sign with
|
if [ -n "$AC_USERNAME" ]; then
|
||||||
if [ -n "$SIGNING_IDENTITY_SHA1" ]; then
|
codesign -s "10BC1FDDEB6CE753550156C0669109FAC49E4D1E" -f -v --timestamp --options=runtime -i "net.defined.nebula" ./release/nebula
|
||||||
codesign -s "$SIGNING_IDENTITY_SHA1" -f -v --timestamp --options=runtime -i "net.defined.nebula" ./release/nebula
|
codesign -s "10BC1FDDEB6CE753550156C0669109FAC49E4D1E" -f -v --timestamp --options=runtime -i "net.defined.nebula-cert" ./release/nebula-cert
|
||||||
codesign -s "$SIGNING_IDENTITY_SHA1" -f -v --timestamp --options=runtime -i "net.defined.nebula-cert" ./release/nebula-cert
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
zip -j release/nebula-darwin.zip release/nebula-cert release/nebula
|
zip -j release/nebula-darwin.zip release/nebula-cert release/nebula
|
||||||
|
|
||||||
if [ -n "$ASC_P8" ]; then
|
if [ -n "$AC_USERNAME" ]; then
|
||||||
xcrun notarytool submit ./release/nebula-darwin.zip --key "$ASC_P8" --key-id "$ASC_KEY_ID" --issuer "$ASC_ISSUER_ID" --wait
|
xcrun notarytool submit ./release/nebula-darwin.zip --team-id "576H3XS7FP" --apple-id "$AC_USERNAME" --password "$AC_PASSWORD" --wait
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Drop the signing key
|
|
||||||
if: always() && env.HAS_SIGNING_CREDS == 'true'
|
|
||||||
run: |
|
|
||||||
# Locked, not deleted: import-codesign-certs deletes it in its own post
|
|
||||||
# step and fails the job if it is already gone. Locked is unusable.
|
|
||||||
security lock-keychain signing_temp.keychain || true
|
|
||||||
rm -f "$ASC_P8"
|
|
||||||
# Nothing later in this job needs AWS
|
|
||||||
python3 -c '
|
|
||||||
import json, os
|
|
||||||
names = json.loads(os.environ.get("SECRETS_LIST_CLEAN_UP") or "[]")
|
|
||||||
names += ["ASC_P8", "SIGNING_IDENTITY_SHA1", "ASC_KEY_ID", "ASC_ISSUER_ID",
|
|
||||||
"AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", "AWS_SESSION_TOKEN"]
|
|
||||||
print("\n".join(f"{n}=" for n in dict.fromkeys(names)))
|
|
||||||
' >> "$GITHUB_ENV"
|
|
||||||
|
|
||||||
- name: Upload artifacts
|
- name: Upload artifacts
|
||||||
uses: actions/upload-artifact@v7
|
uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ require (
|
|||||||
filippo.io/bigmod v0.1.0
|
filippo.io/bigmod v0.1.0
|
||||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be
|
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be
|
||||||
github.com/armon/go-radix v1.0.0
|
github.com/armon/go-radix v1.0.0
|
||||||
github.com/cyberdelia/go-metrics-graphite v0.0.0-20161219230853-39f87cc3b432
|
|
||||||
github.com/flynn/noise v1.1.0
|
github.com/flynn/noise v1.1.0
|
||||||
github.com/gaissmai/bart v0.28.0
|
github.com/gaissmai/bart v0.28.0
|
||||||
github.com/gogo/protobuf v1.3.2
|
github.com/gogo/protobuf v1.3.2
|
||||||
|
|||||||
@@ -19,8 +19,6 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r
|
|||||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
github.com/cyberdelia/go-metrics-graphite v0.0.0-20161219230853-39f87cc3b432 h1:M5QgkYacWj0Xs8MhpIK/5uwU02icXpEoSo9sM2aRCps=
|
|
||||||
github.com/cyberdelia/go-metrics-graphite v0.0.0-20161219230853-39f87cc3b432/go.mod h1:xwIwAxMvYnVrGJPe2FKx5prTrnAjGOD8zvDOnxnrrkM=
|
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
|||||||
+117
@@ -0,0 +1,117 @@
|
|||||||
|
package nebula
|
||||||
|
|
||||||
|
// This file is a trimmed, inlined copy of the graphite exporter from
|
||||||
|
// github.com/cyberdelia/go-metrics-graphite, retaining only the Config type and
|
||||||
|
// the Once entrypoint that Nebula uses. The upstream package has been
|
||||||
|
// unmaintained for 10+ years, so it was vendored here to drop the dependency.
|
||||||
|
// See https://github.com/slackhq/nebula/issues/1831.
|
||||||
|
//
|
||||||
|
// Copyright 2015 Timothée Peignier. All rights reserved.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are met:
|
||||||
|
//
|
||||||
|
// 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
// this list of conditions and the following disclaimer.
|
||||||
|
//
|
||||||
|
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
// this list of conditions and the following disclaimer in the documentation
|
||||||
|
// and/or other materials provided with the distribution.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/rcrowley/go-metrics"
|
||||||
|
)
|
||||||
|
|
||||||
|
// graphiteConfigExport provides a container with configuration parameters for
|
||||||
|
// the Graphite exporter.
|
||||||
|
type graphiteConfigExport struct {
|
||||||
|
Addr *net.TCPAddr // Network address to connect to
|
||||||
|
Registry metrics.Registry // Registry to be exported
|
||||||
|
FlushInterval time.Duration // Flush interval
|
||||||
|
DurationUnit time.Duration // Time conversion unit for durations
|
||||||
|
Prefix string // Prefix to be prepended to metric names
|
||||||
|
Percentiles []float64 // Percentiles to export from timers and histograms
|
||||||
|
}
|
||||||
|
|
||||||
|
// graphiteOnce performs a single submission to Graphite, returning a non-nil
|
||||||
|
// error on failed connections.
|
||||||
|
func graphiteOnce(c graphiteConfigExport) error {
|
||||||
|
now := time.Now().Unix()
|
||||||
|
du := float64(c.DurationUnit)
|
||||||
|
flushSeconds := float64(c.FlushInterval) / float64(time.Second)
|
||||||
|
conn, err := net.DialTCP("tcp", nil, c.Addr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
w := bufio.NewWriter(conn)
|
||||||
|
c.Registry.Each(func(name string, i any) {
|
||||||
|
switch metric := i.(type) {
|
||||||
|
case metrics.Counter:
|
||||||
|
count := metric.Count()
|
||||||
|
fmt.Fprintf(w, "%s.%s.count %d %d\n", c.Prefix, name, count, now)
|
||||||
|
fmt.Fprintf(w, "%s.%s.count_ps %.2f %d\n", c.Prefix, name, float64(count)/flushSeconds, now)
|
||||||
|
case metrics.Gauge:
|
||||||
|
fmt.Fprintf(w, "%s.%s.value %d %d\n", c.Prefix, name, metric.Value(), now)
|
||||||
|
case metrics.GaugeFloat64:
|
||||||
|
fmt.Fprintf(w, "%s.%s.value %f %d\n", c.Prefix, name, metric.Value(), now)
|
||||||
|
case metrics.Histogram:
|
||||||
|
h := metric.Snapshot()
|
||||||
|
ps := h.Percentiles(c.Percentiles)
|
||||||
|
fmt.Fprintf(w, "%s.%s.count %d %d\n", c.Prefix, name, h.Count(), now)
|
||||||
|
fmt.Fprintf(w, "%s.%s.min %d %d\n", c.Prefix, name, h.Min(), now)
|
||||||
|
fmt.Fprintf(w, "%s.%s.max %d %d\n", c.Prefix, name, h.Max(), now)
|
||||||
|
fmt.Fprintf(w, "%s.%s.mean %.2f %d\n", c.Prefix, name, h.Mean(), now)
|
||||||
|
fmt.Fprintf(w, "%s.%s.std-dev %.2f %d\n", c.Prefix, name, h.StdDev(), now)
|
||||||
|
for psIdx, psKey := range c.Percentiles {
|
||||||
|
key := strings.Replace(strconv.FormatFloat(psKey*100.0, 'f', -1, 64), ".", "", 1)
|
||||||
|
fmt.Fprintf(w, "%s.%s.%s-percentile %.2f %d\n", c.Prefix, name, key, ps[psIdx], now)
|
||||||
|
}
|
||||||
|
case metrics.Meter:
|
||||||
|
m := metric.Snapshot()
|
||||||
|
fmt.Fprintf(w, "%s.%s.count %d %d\n", c.Prefix, name, m.Count(), now)
|
||||||
|
fmt.Fprintf(w, "%s.%s.one-minute %.2f %d\n", c.Prefix, name, m.Rate1(), now)
|
||||||
|
fmt.Fprintf(w, "%s.%s.five-minute %.2f %d\n", c.Prefix, name, m.Rate5(), now)
|
||||||
|
fmt.Fprintf(w, "%s.%s.fifteen-minute %.2f %d\n", c.Prefix, name, m.Rate15(), now)
|
||||||
|
fmt.Fprintf(w, "%s.%s.mean %.2f %d\n", c.Prefix, name, m.RateMean(), now)
|
||||||
|
case metrics.Timer:
|
||||||
|
t := metric.Snapshot()
|
||||||
|
ps := t.Percentiles(c.Percentiles)
|
||||||
|
count := t.Count()
|
||||||
|
fmt.Fprintf(w, "%s.%s.count %d %d\n", c.Prefix, name, count, now)
|
||||||
|
fmt.Fprintf(w, "%s.%s.count_ps %.2f %d\n", c.Prefix, name, float64(count)/flushSeconds, now)
|
||||||
|
fmt.Fprintf(w, "%s.%s.min %d %d\n", c.Prefix, name, t.Min()/int64(du), now)
|
||||||
|
fmt.Fprintf(w, "%s.%s.max %d %d\n", c.Prefix, name, t.Max()/int64(du), now)
|
||||||
|
fmt.Fprintf(w, "%s.%s.mean %.2f %d\n", c.Prefix, name, t.Mean()/du, now)
|
||||||
|
fmt.Fprintf(w, "%s.%s.std-dev %.2f %d\n", c.Prefix, name, t.StdDev()/du, now)
|
||||||
|
for psIdx, psKey := range c.Percentiles {
|
||||||
|
key := strings.Replace(strconv.FormatFloat(psKey*100.0, 'f', -1, 64), ".", "", 1)
|
||||||
|
fmt.Fprintf(w, "%s.%s.%s-percentile %.2f %d\n", c.Prefix, name, key, ps[psIdx]/du, now)
|
||||||
|
}
|
||||||
|
fmt.Fprintf(w, "%s.%s.one-minute %.2f %d\n", c.Prefix, name, t.Rate1(), now)
|
||||||
|
fmt.Fprintf(w, "%s.%s.five-minute %.2f %d\n", c.Prefix, name, t.Rate5(), now)
|
||||||
|
fmt.Fprintf(w, "%s.%s.fifteen-minute %.2f %d\n", c.Prefix, name, t.Rate15(), now)
|
||||||
|
fmt.Fprintf(w, "%s.%s.mean-rate %.2f %d\n", c.Prefix, name, t.RateMean(), now)
|
||||||
|
}
|
||||||
|
w.Flush()
|
||||||
|
})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -13,7 +13,6 @@ import (
|
|||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
graphite "github.com/cyberdelia/go-metrics-graphite"
|
|
||||||
mp "github.com/nbrownus/go-metrics-prometheus"
|
mp "github.com/nbrownus/go-metrics-prometheus"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||||
@@ -253,7 +252,7 @@ func (s *statsServer) buildRuntime(cfg statsConfig) ([]func(), *http.Server) {
|
|||||||
// loadStatsConfig already resolved and validated the address; re-parse
|
// loadStatsConfig already resolved and validated the address; re-parse
|
||||||
// the resolved form (no DNS lookup) to get a *net.TCPAddr.
|
// the resolved form (no DNS lookup) to get a *net.TCPAddr.
|
||||||
addr, _ := net.ResolveTCPAddr(cfg.graphite.protocol, cfg.graphite.resolvedAddr)
|
addr, _ := net.ResolveTCPAddr(cfg.graphite.protocol, cfg.graphite.resolvedAddr)
|
||||||
gcfg := graphite.Config{
|
gcfg := graphiteConfigExport{
|
||||||
Addr: addr,
|
Addr: addr,
|
||||||
Registry: metrics.DefaultRegistry,
|
Registry: metrics.DefaultRegistry,
|
||||||
FlushInterval: cfg.interval,
|
FlushInterval: cfg.interval,
|
||||||
@@ -262,7 +261,7 @@ func (s *statsServer) buildRuntime(cfg statsConfig) ([]func(), *http.Server) {
|
|||||||
Percentiles: []float64{0.5, 0.75, 0.95, 0.99, 0.999},
|
Percentiles: []float64{0.5, 0.75, 0.95, 0.99, 0.999},
|
||||||
}
|
}
|
||||||
captureFns = append(captureFns, func() {
|
captureFns = append(captureFns, func() {
|
||||||
if err := graphite.Once(gcfg); err != nil {
|
if err := graphiteOnce(gcfg); err != nil {
|
||||||
s.l.Error("Graphite export failed", "error", err)
|
s.l.Error("Graphite export failed", "error", err)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
+1
-1
@@ -371,7 +371,7 @@ func waitForListening(t *testing.T, addr string) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// graphiteSink is a minimal TCP accept-and-discard server so graphite.Once
|
// graphiteSink is a minimal TCP accept-and-discard server so graphiteOnce
|
||||||
// calls in tests don't spam error logs or wedge on connection refused.
|
// calls in tests don't spam error logs or wedge on connection refused.
|
||||||
type graphiteSink struct {
|
type graphiteSink struct {
|
||||||
ln net.Listener
|
ln net.Listener
|
||||||
|
|||||||
Reference in New Issue
Block a user