Skip to content

Commit

Permalink
feat: send telemetry through our proxy
Browse files Browse the repository at this point in the history
  • Loading branch information
palkan committed Oct 4, 2024
1 parent 3e19ee9 commit 07b8cf4
Show file tree
Hide file tree
Showing 6 changed files with 147 additions and 71 deletions.
96 changes: 49 additions & 47 deletions .github/workflows/release-binaries.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ jobs:
GO111MODULE: on
CGO_ENABLED: "0"
GOFLAGS: "-mod=vendor"
ANYCABLE_TELEMETRY_TOKEN: ${{ secrets.ANYCABLE_TELEMETRY_TOKEN }}
steps:
- uses: actions/checkout@v2
- name: Install system deps
Expand Down Expand Up @@ -41,17 +42,17 @@ jobs:
echo ::set-output name=VERSION::${GITHUB_REF#refs/tags/v}
- name: Build binaries
run: |
env GOOS=windows GOARCH=amd64 go build -ldflags "-s -w -X github.com/anycable/anycable-go/version.version=${{ steps.version.outputs.VERSION }} -X github.com/anycable/anycable-go/version.sha=$(echo "$GITHUB_SHA" | cut -c -7)" -a -o dist/anycable-go-win-amd64.exe cmd/anycable-go/main.go
env GOOS=freebsd GOARCH=arm go build -ldflags "-s -w -X github.com/anycable/anycable-go/version.version=${{ steps.version.outputs.VERSION }} -X github.com/anycable/anycable-go/version.sha=$(echo "$GITHUB_SHA" | cut -c -7)" -a -o dist/anycable-go-freebsd-arm cmd/anycable-go/main.go
env GOOS=freebsd GOARCH=amd64 go build -ldflags "-s -w -X github.com/anycable/anycable-go/version.version=${{ steps.version.outputs.VERSION }} -X github.com/anycable/anycable-go/version.sha=$(echo "$GITHUB_SHA" | cut -c -7)" -a -o dist/anycable-go-freebsd-amd64 cmd/anycable-go/main.go
env GOOS=linux GOARCH=arm64 go build -ldflags "-s -w -X github.com/anycable/anycable-go/version.version=${{ steps.version.outputs.VERSION }} -X github.com/anycable/anycable-go/version.sha=$(echo "$GITHUB_SHA" | cut -c -7)" -a -o dist/anycable-go-linux-arm64 cmd/anycable-go/main.go
env GOOS=linux GOARCH=amd64 go build -ldflags "-s -w -X github.com/anycable/anycable-go/version.version=${{ steps.version.outputs.VERSION }} -X github.com/anycable/anycable-go/version.sha=$(echo "$GITHUB_SHA" | cut -c -7)" -a -o dist/anycable-go-linux-amd64 cmd/anycable-go/main.go
env GOOS=windows GOARCH=amd64 go build -ldflags "-s -w -X github.com/anycable/anycable-go/telemetry.auth=$(echo "$ANYCABLE_TELEMETRY_TOKEN") -X github.com/anycable/anycable-go/version.version=${{ steps.version.outputs.VERSION }} -X github.com/anycable/anycable-go/version.sha=$(echo "$GITHUB_SHA" | cut -c -7)" -a -o dist/anycable-go-win-amd64.exe cmd/anycable-go/main.go
env GOOS=freebsd GOARCH=arm go build -ldflags "-s -w -X github.com/anycable/anycable-go/telemetry.auth=$(echo "$ANYCABLE_TELEMETRY_TOKEN") -X github.com/anycable/anycable-go/version.version=${{ steps.version.outputs.VERSION }} -X github.com/anycable/anycable-go/version.sha=$(echo "$GITHUB_SHA" | cut -c -7)" -a -o dist/anycable-go-freebsd-arm cmd/anycable-go/main.go
env GOOS=freebsd GOARCH=amd64 go build -ldflags "-s -w -X github.com/anycable/anycable-go/telemetry.auth=$(echo "$ANYCABLE_TELEMETRY_TOKEN") -X github.com/anycable/anycable-go/version.version=${{ steps.version.outputs.VERSION }} -X github.com/anycable/anycable-go/version.sha=$(echo "$GITHUB_SHA" | cut -c -7)" -a -o dist/anycable-go-freebsd-amd64 cmd/anycable-go/main.go
env GOOS=linux GOARCH=arm64 go build -ldflags "-s -w -X github.com/anycable/anycable-go/telemetry.auth=$(echo "$ANYCABLE_TELEMETRY_TOKEN") -X github.com/anycable/anycable-go/version.version=${{ steps.version.outputs.VERSION }} -X github.com/anycable/anycable-go/version.sha=$(echo "$GITHUB_SHA" | cut -c -7)" -a -o dist/anycable-go-linux-arm64 cmd/anycable-go/main.go
env GOOS=linux GOARCH=amd64 go build -ldflags "-s -w -X github.com/anycable/anycable-go/telemetry.auth=$(echo "$ANYCABLE_TELEMETRY_TOKEN") -X github.com/anycable/anycable-go/version.version=${{ steps.version.outputs.VERSION }} -X github.com/anycable/anycable-go/version.sha=$(echo "$GITHUB_SHA" | cut -c -7)" -a -o dist/anycable-go-linux-amd64 cmd/anycable-go/main.go
dist/anycable-go-linux-amd64 -v
- name: Build binary with MRuby
env:
CGO_ENABLED: "1"
run: |
env GOOS=linux GOARCH=amd64 go build -tags mrb -ldflags "-s -w -X github.com/anycable/anycable-go/version.version=${{ steps.version.outputs.VERSION }} -X github.com/anycable/anycable-go/version.sha=$(echo "$GITHUB_SHA" | cut -c -7)" -a -o dist/anycable-go-mrb-linux-amd64 cmd/anycable-go/main.go
env GOOS=linux GOARCH=amd64 go build -tags mrb -ldflags "-s -w -X github.com/anycable/anycable-go/telemetry.auth=$(echo "$ANYCABLE_TELEMETRY_TOKEN") -X github.com/anycable/anycable-go/version.version=${{ steps.version.outputs.VERSION }} -X github.com/anycable/anycable-go/version.sha=$(echo "$GITHUB_SHA" | cut -c -7)" -a -o dist/anycable-go-mrb-linux-amd64 cmd/anycable-go/main.go
dist/anycable-go-mrb-linux-amd64 -v
- uses: xresloader/upload-to-github-release@v1
env:
Expand All @@ -76,45 +77,46 @@ jobs:
GO111MODULE: on
CGO_ENABLED: "0"
GOFLAGS: "-mod=vendor"
ANYCABLE_TELEMETRY_TOKEN: ${{ secrets.ANYCABLE_TELEMETRY_TOKEN }}
steps:
- uses: actions/checkout@v2
- name: Install system deps
run: |
brew install bison
- uses: actions/cache@v1
with:
path: vendor
key: vendor-${{ hashFiles('**/go.sum') }}
restore-keys: |
vendor-
- uses: actions/setup-go@v4
with:
go-version-file: go.mod
- run: go mod vendor
- uses: ruby/setup-ruby@v1
with:
# Use <3.0 since go-mruby's Rakefile has some problems with keyword arguments compatibility
ruby-version: 2.7
bundler-cache: true
- name: Build mruby
run: bash -c '(cd vendor/github.com/mitchellh/go-mruby && MRUBY_CONFIG=../../../../../../etc/build_config.rb make libmruby.a)'
- name: Set VERSION (if any)
if: ${{ contains(github.ref, 'refs/tags/v') }}
id: version
run: |
echo ::set-output name=VERSION::${GITHUB_REF#refs/tags/v}
- name: Build binaries for MacOS
run: |
env GOOS=darwin GOARCH=${{ matrix.suffix }} go build -ldflags "-s -w -X github.com/anycable/anycable-go/version.version=${{ steps.version.outputs.VERSION }} -X github.com/anycable/anycable-go/version.sha=$(echo "$GITHUB_SHA" | cut -c -7)" -a -o dist/anycable-go-darwin-${{ matrix.suffix }} cmd/anycable-go/main.go
- name: Build binaries with MRuby for MacOS
env:
CGO_ENABLED: "1"
run: |
env GOOS=darwin GOARCH=${{ matrix.suffix }} go build -tags mrb -ldflags "-s -w -X github.com/anycable/anycable-go/version.version=${{ steps.version.outputs.VERSION }} -X github.com/anycable/anycable-go/version.sha=$(echo "$GITHUB_SHA" | cut -c -7)" -a -o dist/anycable-go-mrb-darwin-${{ matrix.suffix }} cmd/anycable-go/main.go
dist/anycable-go-mrb-darwin-${{ matrix.suffix }} -v
- uses: xresloader/upload-to-github-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
file: "dist/anycable-go-*"
tags: true
- uses: actions/checkout@v2
- name: Install system deps
run: |
brew install bison
- uses: actions/cache@v1
with:
path: vendor
key: vendor-${{ hashFiles('**/go.sum') }}
restore-keys: |
vendor-
- uses: actions/setup-go@v4
with:
go-version-file: go.mod
- run: go mod vendor
- uses: ruby/setup-ruby@v1
with:
# Use <3.0 since go-mruby's Rakefile has some problems with keyword arguments compatibility
ruby-version: 2.7
bundler-cache: true
- name: Build mruby
run: bash -c '(cd vendor/github.com/mitchellh/go-mruby && MRUBY_CONFIG=../../../../../../etc/build_config.rb make libmruby.a)'
- name: Set VERSION (if any)
if: ${{ contains(github.ref, 'refs/tags/v') }}
id: version
run: |
echo ::set-output name=VERSION::${GITHUB_REF#refs/tags/v}
- name: Build binaries for MacOS
run: |
env GOOS=darwin GOARCH=${{ matrix.suffix }} go build -ldflags "-s -w -X github.com/anycable/anycable-go/telemetry.auth=$(echo "$ANYCABLE_TELEMETRY_TOKEN") -X github.com/anycable/anycable-go/version.version=${{ steps.version.outputs.VERSION }} -X github.com/anycable/anycable-go/version.sha=$(echo "$GITHUB_SHA" | cut -c -7)" -a -o dist/anycable-go-darwin-${{ matrix.suffix }} cmd/anycable-go/main.go
- name: Build binaries with MRuby for MacOS
env:
CGO_ENABLED: "1"
run: |
env GOOS=darwin GOARCH=${{ matrix.suffix }} go build -tags mrb -ldflags "-s -w -X github.com/anycable/anycable-go/telemetry.auth=$(echo "$ANYCABLE_TELEMETRY_TOKEN") -X github.com/anycable/anycable-go/version.version=${{ steps.version.outputs.VERSION }} -X github.com/anycable/anycable-go/version.sha=$(echo "$GITHUB_SHA" | cut -c -7)" -a -o dist/anycable-go-mrb-darwin-${{ matrix.suffix }} cmd/anycable-go/main.go
dist/anycable-go-mrb-darwin-${{ matrix.suffix }} -v
- uses: xresloader/upload-to-github-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
file: "dist/anycable-go-*"
tags: true
7 changes: 4 additions & 3 deletions .github/workflows/release-docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ jobs:
GO111MODULE: on
CGO_ENABLED: "0"
GOFLAGS: "-mod=vendor"
ANYCABLE_TELEMETRY_TOKEN: ${{ secrets.ANYCABLE_TELEMETRY_TOKEN }}
steps:
- uses: actions/checkout@v4
- name: Install system deps
Expand Down Expand Up @@ -39,8 +40,8 @@ jobs:
cp /etc/ssl/certs/ca-certificates.crt ./.docker/ca-certificates.crt
- name: Build binary
run: |
env GOOS=linux GOARCH=arm64 go build -ldflags "-s -w -X github.com/anycable/anycable-go/version.version=${{ steps.version.outputs.VERSION }} -X github.com/anycable/anycable-go/version.sha=$(echo "$GITHUB_SHA" | cut -c -7)" -a -o .docker/linux/arm64/anycable-go cmd/anycable-go/main.go
env GOOS=linux GOARCH=amd64 go build -ldflags "-s -w -X github.com/anycable/anycable-go/version.version=${{ steps.version.outputs.VERSION }} -X github.com/anycable/anycable-go/version.sha=$(echo "$GITHUB_SHA" | cut -c -7)" -a -o .docker/linux/amd64/anycable-go cmd/anycable-go/main.go
env GOOS=linux GOARCH=arm64 go build -ldflags "-s -w -X github.com/anycable/anycable-go/telemetry.auth=$(echo "$ANYCABLE_TELEMETRY_TOKEN") -X github.com/anycable/anycable-go/version.version=${{ steps.version.outputs.VERSION }} -X github.com/anycable/anycable-go/version.sha=$(echo "$GITHUB_SHA" | cut -c -7)" -a -o .docker/linux/arm64/anycable-go cmd/anycable-go/main.go
env GOOS=linux GOARCH=amd64 go build -ldflags "-s -w -X github.com/anycable/anycable-go/telemetry.auth=$(echo "$ANYCABLE_TELEMETRY_TOKEN") -X github.com/anycable/anycable-go/version.version=${{ steps.version.outputs.VERSION }} -X github.com/anycable/anycable-go/version.sha=$(echo "$GITHUB_SHA" | cut -c -7)" -a -o .docker/linux/amd64/anycable-go cmd/anycable-go/main.go
.docker/linux/amd64/anycable-go -v
- uses: docker/setup-buildx-action@v2
- uses: docker/login-action@v2
Expand Down Expand Up @@ -113,7 +114,7 @@ jobs:
env:
CGO_ENABLED: "1"
run: |
env GOOS=linux GOARCH=amd64 go build -tags mrb -ldflags "-s -w -X github.com/anycable/anycable-go/version.version=${{ steps.version.outputs.VERSION }} -X github.com/anycable/anycable-go/version.sha=$(echo "$GITHUB_SHA" | cut -c -7)" -a -o .docker/linux/amd64/anycable-go cmd/anycable-go/main.go
env GOOS=linux GOARCH=amd64 go build -tags mrb -ldflags "-s -w -X github.com/anycable/anycable-go/telemetry.auth=$(echo "$ANYCABLE_TELEMETRY_TOKEN") -X github.com/anycable/anycable-go/version.version=${{ steps.version.outputs.VERSION }} -X github.com/anycable/anycable-go/version.sha=$(echo "$GITHUB_SHA" | cut -c -7)" -a -o .docker/linux/amd64/anycable-go cmd/anycable-go/main.go
.docker/linux/amd64/anycable-go -v
- name: Prepare Docker metadata and versions for mrb image
id: meta-mrb
Expand Down
8 changes: 8 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@ ifndef ANYCABLE_DISABLE_TELEMETRY
export ANYCABLE_DISABLE_TELEMETRY=true
endif

ifndef ANYCABLE_TELEMETRY_URL
export ANYCABLE_TELEMETRY_URL=http://localhost:4343
endif

ifndef ANYCABLE_TELEMETRY_DEBUG
export ANYCABLE_TELEMETRY_DEBUG=1
endif

BUILD_ARGS ?=
TEST_FLAGS=
TEST_BUILD_FLAGS=
Expand Down
3 changes: 3 additions & 0 deletions cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,9 @@ func (r *Runner) runNode() (*node.Node, error) {

if r.telemetryEnabled {
telemetryConfig := telemetry.NewConfig()
if customTelemetryUrl := os.Getenv("ANYCABLE_TELEMETRY_URL"); customTelemetryUrl != "" {
telemetryConfig.Endpoint = customTelemetryUrl
}
tracker := telemetry.NewTracker(metrics, r.config, telemetryConfig)

r.log.With("context", "telemetry").Info(tracker.Announce())
Expand Down
10 changes: 8 additions & 2 deletions telemetry/config.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
package telemetry

Check failure on line 1 in telemetry/config.go

View workflow job for this annotation

GitHub Actions / lint

: # github.com/anycable/anycable-go/telemetry [github.com/anycable/anycable-go/telemetry.test]

import "os"

type Config struct {
Token string
Endpoint string
Debug bool
}

var authToken = "secret" // make it overridable during build time

func NewConfig() *Config {
return &Config{
Token: "phc_fc9VFWdFAAm5gSlCodHq93iaxxnTTKbjOwsWgAS1FMP",
Endpoint: "https://app.posthog.com",
Token: authToken,
Endpoint: "https://telemetry.anycable.io",
Debug: os.Getenv("ANYCABLE_TELEMETRY_DEBUG") == "1",
}
}
94 changes: 75 additions & 19 deletions telemetry/telemetry.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package telemetry

import (
"bytes"
"context"
"encoding/json"
"maps"
"net/http"
"os"
"runtime"
"sync"
Expand All @@ -14,6 +17,7 @@ import (
"github.com/anycable/anycable-go/version"
"github.com/hofstadter-io/cinful"
"github.com/posthog/posthog-go"
"golang.org/x/exp/slog"

nanoid "github.com/matoous/go-nanoid"
)
Expand All @@ -23,36 +27,44 @@ const (
)

type Tracker struct {
id string
client posthog.Client
id string
client *http.Client

// Remote service configuration
url string
authToken string

instrumenter *metrics.Metrics
config *config.Config
timer *time.Timer

closed bool

mu sync.Mutex
mu sync.Mutex
logger *slog.Logger

// Observed metrics values
observations map[string]interface{}
}

type noopLogger struct{}
func NewTracker(instrumenter *metrics.Metrics, c *config.Config, tc *Config) *Tracker {
id, _ := nanoid.Nanoid(8)

client := &http.Client{}

func (l noopLogger) Logf(format string, args ...interface{}) {}
func (l noopLogger) Errorf(format string, args ...interface{}) {}
logLevel := slog.LevelInfo

func NewTracker(instrumenter *metrics.Metrics, c *config.Config, tc *Config) *Tracker {
client, _ := posthog.NewWithConfig(tc.Token, posthog.Config{
Endpoint: tc.Endpoint,
// set to no-op to avoid logging
Logger: noopLogger{},
})
if tc.Debug {
logLevel = slog.LevelDebug
}

id, _ := nanoid.Nanoid(8)
logger := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: logLevel}))

return &Tracker{
client: client,
url: tc.Endpoint,
authToken: tc.Token,
logger: logger,
config: c,
instrumenter: instrumenter,
id: id,
Expand Down Expand Up @@ -89,19 +101,63 @@ func (t *Tracker) Shutdown(ctx context.Context) error {
t.timer.Stop()
}

return t.client.Close()
t.client.CloseIdleConnections()

return nil
}

func (t *Tracker) Send(event string, props map[string]interface{}) {
t.logger.Debug("send telemetry event", "event", event)

// Avoid storing IP address
props["$ip"] = nil
props["distinct_id"] = t.id
props["event"] = event

ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
defer cancel()

payload, err := json.Marshal(props)

_ = t.client.Enqueue(posthog.Capture{
DistinctId: t.id,
Event: event,
Properties: props,
})
if err != nil {
t.logger.Debug("failed to marshal telemetry payload", "err", err)
return
}

req, err := http.NewRequestWithContext(ctx, "POST", t.url, bytes.NewReader(payload))
if err != nil {
return
}

req.Header.Set("Content-Type", "application/json")

if t.authToken != "" {
req.Header.Set("Authorization", t.authToken)
}

res, err := t.client.Do(req)

if err != nil {
if ctx.Err() != nil {
t.logger.Debug("timed out to send telemetry data")
return
}

t.logger.Debug("failed to perform telemetry request", "err", err)
return
}

defer res.Body.Close()

if res.StatusCode == http.StatusUnauthorized {
t.logger.Debug("telemetry authenticated failed")
return
}

if res.StatusCode != http.StatusOK {
t.logger.Debug("telemetry request failed", "status", res.StatusCode)
return
}
}

func (t *Tracker) monitorUsage() {
Expand Down

0 comments on commit 07b8cf4

Please sign in to comment.