Skip to content

Commit 33be919

Browse files
authored
Initial implementation of offline mode (#3026)
offline mode
1 parent 68dcb27 commit 33be919

File tree

7 files changed

+1064
-22
lines changed

7 files changed

+1064
-22
lines changed

flags/flags.go

+17-1
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ import (
2222
"time"
2323

2424
"github.com/alecthomas/kong"
25-
"go.opentelemetry.io/ebpf-profiler/tracer"
2625
log "github.com/sirupsen/logrus"
26+
"go.opentelemetry.io/ebpf-profiler/tracer"
2727
_ "google.golang.org/grpc/encoding/proto"
2828
)
2929

@@ -121,6 +121,8 @@ type Flags struct {
121121
Hidden FlagsHidden `embed:"" hidden:"" prefix:""`
122122

123123
BPF FlagsBPF `embed:"" prefix:"bpf-"`
124+
125+
OfflineMode FlagsOfflineMode `embed:"" prefix:"offline-mode-"`
124126
}
125127

126128
type ExitCode int
@@ -192,6 +194,14 @@ func (f Flags) Validate() ExitCode {
192194
}
193195
}
194196

197+
if len(f.OfflineMode.StoragePath) > 0 && !f.OfflineMode.Upload && (len(f.RemoteStore.Address) > 0 || len(f.OTLP.Address) > 0) {
198+
return ParseError("Specified both offline mode and a remote store; this configuration is invalid.")
199+
}
200+
201+
if f.OfflineMode.Upload && len(f.OfflineMode.StoragePath) == 0 {
202+
return ParseError("Specified --offline-mode-upload without --offline-mode-storage-path.")
203+
}
204+
195205
return ExitSuccess
196206
}
197207

@@ -343,3 +353,9 @@ type FlagsBPF struct {
343353
VerifierLogLevel uint32 `default:"0" help:"Log level of the eBPF verifier output (0,1,2). Default is 0."`
344354
VerifierLogSize int `default:"0" help:"[deprecated] Unused."`
345355
}
356+
357+
type FlagsOfflineMode struct {
358+
StoragePath string `help:"Enables offline mode, with the data stored at the given path."`
359+
RotationInterval time.Duration `default:"10m" help:"How often to rotate and compress the offline mode log."`
360+
Upload bool `help:"Run the uploader for data written in offline mode."`
361+
}

flags/grpc.go

+1-2
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ import (
1212
"github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/logging"
1313
"github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/retry"
1414
"github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/timeout"
15-
"go.opentelemetry.io/ebpf-profiler/libpf"
1615
"github.com/prometheus/client_golang/prometheus"
1716
log "github.com/sirupsen/logrus"
1817
tracing "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
18+
"go.opentelemetry.io/ebpf-profiler/libpf"
1919
"go.opentelemetry.io/otel/propagation"
2020
"go.opentelemetry.io/otel/trace"
2121
"google.golang.org/grpc"
@@ -79,7 +79,6 @@ func (f FlagsRemoteStore) setupGrpcConnection(parent context.Context, metrics *g
7979
grpc.WithReturnConnectionError(),
8080
}
8181

82-
// TLS
8382
if f.Insecure {
8483
opts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials()))
8584
} else {

go.mod

+2-1
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,13 @@ require (
1515
github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be
1616
github.com/containerd/containerd v1.7.20
1717
github.com/docker/docker v27.1.1+incompatible
18+
github.com/dustin/go-humanize v1.0.1
1819
github.com/elastic/go-freelru v0.15.0
1920
github.com/gogo/protobuf v1.3.2
2021
github.com/golang/snappy v0.0.4
2122
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1
2223
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0
23-
github.com/klauspost/compress v1.17.9
24+
github.com/klauspost/compress v1.17.11
2425
github.com/prometheus/client_golang v1.19.1
2526
github.com/prometheus/common v0.54.0
2627
github.com/prometheus/prometheus v0.53.1

go.sum

+4-2
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ
9191
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA=
9292
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
9393
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
94+
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
95+
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
9496
github.com/elastic/go-freelru v0.15.0 h1:Jo1aY8JAvpyxbTDJEudrsBfjFDaALpfVv8mxuh9sfvI=
9597
github.com/elastic/go-freelru v0.15.0/go.mod h1:bSdWT4M0lW79K8QbX6XY2heQYSCqD7THoYf82pT/H3I=
9698
github.com/elastic/go-perf v0.0.0-20241016160959-1342461adb4a h1:ymmtaN4bVCmKKeu4XEf6JEWNZKRXPMng1zjpKd+8rCU=
@@ -197,8 +199,8 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr
197199
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
198200
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
199201
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
200-
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
201-
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
202+
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
203+
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
202204
github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM=
203205
github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
204206
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=

main.go

+43-10
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,13 @@ import (
4646
"go.opentelemetry.io/otel/trace"
4747
"go.opentelemetry.io/otel/trace/noop"
4848
"golang.org/x/sys/unix"
49+
"google.golang.org/grpc"
4950

5051
"github.com/parca-dev/parca-agent/analytics"
5152
"github.com/parca-dev/parca-agent/config"
5253
"github.com/parca-dev/parca-agent/flags"
5354
"github.com/parca-dev/parca-agent/reporter"
55+
"github.com/parca-dev/parca-agent/uploader"
5456
)
5557

5658
var (
@@ -136,6 +138,14 @@ func mainWithExitCode() flags.ExitCode {
136138
return code
137139
}
138140

141+
if f.OfflineMode.Upload {
142+
code, err := uploader.OfflineModeDoUpload(f)
143+
if err != nil {
144+
log.Errorf("failed to upload offline mode logs: %v", err)
145+
}
146+
return code
147+
}
148+
139149
reg := prometheus.NewRegistry()
140150
reg.MustRegister(
141151
collectors.NewBuildInfoCollector(),
@@ -164,12 +174,17 @@ func mainWithExitCode() flags.ExitCode {
164174
}
165175
}
166176

167-
grpcConn, err := f.RemoteStore.WaitGrpcEndpoint(ctx, reg, tp)
168-
if err != nil {
169-
log.Errorf("failed to connect to server: %v", err)
170-
return flags.ExitFailure
177+
isOfflineMode := len(f.OfflineMode.StoragePath) > 0
178+
179+
var grpcConn *grpc.ClientConn
180+
if !isOfflineMode {
181+
grpcConn, err = f.RemoteStore.WaitGrpcEndpoint(ctx, reg, tp)
182+
if err != nil {
183+
log.Errorf("failed to connect to server: %v", err)
184+
return flags.ExitFailure
185+
}
186+
defer grpcConn.Close()
171187
}
172-
defer grpcConn.Close()
173188

174189
presentCores, err := numcpus.GetPresent()
175190
if err != nil {
@@ -291,17 +306,32 @@ func mainWithExitCode() flags.ExitCode {
291306
intervals := times.New(5*time.Second, f.Profiling.Duration, f.Profiling.ProbabilisticInterval)
292307
times.StartRealtimeSync(mainCtx, f.ClockSyncInterval)
293308

309+
var client profilestoregrpc.ProfileStoreServiceClient
310+
var debuginfoClient debuginfogrpc.DebuginfoServiceClient
311+
if grpcConn != nil {
312+
client = profilestoregrpc.NewProfileStoreServiceClient(grpcConn)
313+
debuginfoClient = debuginfogrpc.NewDebuginfoServiceClient(grpcConn)
314+
}
315+
316+
var offlineModeConfig *reporter.OfflineModeConfig
317+
if isOfflineMode {
318+
offlineModeConfig = &reporter.OfflineModeConfig{
319+
StoragePath: f.OfflineMode.StoragePath,
320+
RotationInterval: f.OfflineMode.RotationInterval,
321+
}
322+
}
323+
294324
// Network operations to CA start here
295325
// Connect to the collection agent
296326
parcaReporter, err := reporter.New(
297327
memory.DefaultAllocator,
298-
profilestoregrpc.NewProfileStoreServiceClient(grpcConn),
299-
debuginfogrpc.NewDebuginfoServiceClient(grpcConn),
328+
client,
329+
debuginfoClient,
300330
externalLabels,
301331
f.Profiling.Duration,
302332
f.Debuginfo.Strip,
303333
f.Debuginfo.UploadMaxParallel,
304-
f.Debuginfo.UploadDisable,
334+
f.Debuginfo.UploadDisable || isOfflineMode,
305335
int64(f.Profiling.CPUSamplingFrequency),
306336
traceHandlerCacheSize,
307337
f.Debuginfo.UploadQueueSize,
@@ -310,6 +340,7 @@ func mainWithExitCode() flags.ExitCode {
310340
relabelConfigs,
311341
buildInfo.VcsRevision,
312342
reg,
343+
offlineModeConfig,
313344
)
314345
if err != nil {
315346
return flags.Failure("Failed to start reporting: %v", err)
@@ -413,8 +444,10 @@ func mainWithExitCode() flags.ExitCode {
413444

414445
log.Info("Stop processing ...")
415446
rep.Stop()
416-
if err := grpcConn.Close(); err != nil {
417-
log.Fatalf("Stopping connection of OTLP client client failed: %v", err)
447+
if grpcConn != nil {
448+
if err := grpcConn.Close(); err != nil {
449+
log.Fatalf("Stopping connection of OTLP client client failed: %v", err)
450+
}
418451
}
419452

420453
log.Info("Exiting ...")

0 commit comments

Comments
 (0)