From c6f896eda2151a8b9225b31f8e0dc419c456701b Mon Sep 17 00:00:00 2001 From: Frederic Branczyk Date: Thu, 31 Aug 2023 14:38:32 +0200 Subject: [PATCH] Allow overriding timestamps to current timestamp --- .golangci.yml | 18 +++++++++++------- README.md | 2 ++ cmd/parca-push/main.go | 33 ++++++++++++++++++++++++++------- go.mod | 1 + go.sum | 2 ++ 5 files changed, 42 insertions(+), 14 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 5f51e6e..6b239e3 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -44,13 +44,17 @@ issues: linters-settings: depguard: - list-type: blacklist - include-go-root: true - packages-with-error-message: - - sync/atomic: "Use go.uber.org/atomic instead of sync/atomic" - - github.com/stretchr/testify/assert: "Use github.com/stretchr/testify/require instead of github.com/stretchr/testify/assert" - - github.com/go-kit/kit/log: "Use github.com/go-kit/log instead of github.com/go-kit/kit/log" - - github.com/pkg/errors: "Use fmt.Errorf instead" + rules: + Main: + deny: + - pkg: sync/atomic + desc: Use go.uber.org/atomic instead of sync/atomic + - pkg: github.com/stretchr/testify/assert + desc: Use github.com/stretchr/testify/require instead of github.com/stretchr/testify/assert + - pkg: github.com/go-kit/kit/log + desc: Use github.com/go-kit/log instead of github.com/go-kit/kit/log + - pkg: github.com/pkg/errors + desc: Use fmt.Errorf instead errcheck: exclude: ./.errcheck_excludes.txt goimports: diff --git a/README.md b/README.md index e964681..cd62177 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,8 @@ Flags: --labels=node=foo --normalized Whether the profile sample addresses are already normalized by the mapping offset. + --override-timestamp Update the timestamp in the pprof profile to be + the current time. --remote-store-address=STRING gRPC address to send profiles and symbols to. --remote-store-bearer-token=STRING diff --git a/cmd/parca-push/main.go b/cmd/parca-push/main.go index 1d29c98..7ec0bc7 100644 --- a/cmd/parca-push/main.go +++ b/cmd/parca-push/main.go @@ -15,13 +15,16 @@ package main import ( + "bytes" "context" "crypto/tls" "fmt" "io" "os" + "time" "github.com/alecthomas/kong" + "github.com/google/pprof/profile" grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus" grun "github.com/oklog/run" profilestorepb "github.com/parca-dev/parca/gen/proto/go/parca/profilestore/v1alpha1" @@ -32,9 +35,10 @@ import ( ) type flags struct { - Path string `kong:"arg,help='Path to the profile data.'"` - Labels map[string]string `kong:"help='Labels to attach to the profile data. For example --labels=__name__=process_cpu --labels=node=foo',short='l'"` - Normalized bool `kong:"help='Whether the profile sample addresses are already normalized by the mapping offset.',default='false'"` + Path string `kong:"arg,help='Path to the profile data.'"` + Labels map[string]string `kong:"help='Labels to attach to the profile data. For example --labels=__name__=process_cpu --labels=node=foo',short='l'"` + Normalized bool `kong:"help='Whether the profile sample addresses are already normalized by the mapping offset.',default='false'"` + OverrideTimestamp bool `kong:"help='Update the timestamp in the pprof profile to be the current time.'"` RemoteStore FlagsRemoteStore `embed:"" prefix:"remote-store-"` } @@ -75,19 +79,34 @@ func run(flags flags) error { } defer conn.Close() - var profile []byte + var profileContent []byte if flags.Path == "-" { - profile, err = io.ReadAll(os.Stdin) + profileContent, err = io.ReadAll(os.Stdin) if err != nil { return fmt.Errorf("read profile from stdin: %w", err) } } else { - profile, err = os.ReadFile(flags.Path) + profileContent, err = os.ReadFile(flags.Path) if err != nil { return fmt.Errorf("read profile file: %w", err) } } + p, err := profile.ParseData(profileContent) + if err != nil { + return fmt.Errorf("parse pprof profile: %w", err) + } + + if flags.OverrideTimestamp { + now := time.Now() + p.TimeNanos = now.UnixNano() + buf := bytes.NewBuffer(nil) + if err := p.Write(buf); err != nil { + return fmt.Errorf("serialize pprof profile: %w", err) + } + profileContent = buf.Bytes() + } + profilestoreClient := profilestorepb.NewProfileStoreServiceClient(conn) _, err = profilestoreClient.WriteRaw(ctx, &profilestorepb.WriteRawRequest{ Series: []*profilestorepb.RawProfileSeries{{ @@ -95,7 +114,7 @@ func run(flags flags) error { Labels: labels, }, Samples: []*profilestorepb.RawSample{{ - RawProfile: profile, + RawProfile: profileContent, }}, }}, Normalized: flags.Normalized, diff --git a/go.mod b/go.mod index 0e14417..9a538b8 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.19 require ( github.com/alecthomas/kong v0.7.1 + github.com/google/pprof v0.0.0-20221203041831-ce31453925ec github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 github.com/oklog/run v1.1.0 github.com/parca-dev/parca v0.15.0 diff --git a/go.sum b/go.sum index 8040f6d..7a2a990 100644 --- a/go.sum +++ b/go.sum @@ -15,6 +15,8 @@ github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/pprof v0.0.0-20221203041831-ce31453925ec h1:fR20TYVVwhK4O7r7y+McjRYyaTH6/vjwJOajE+XhlzM= +github.com/google/pprof v0.0.0-20221203041831-ce31453925ec/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway/v2 v2.14.0 h1:t7uX3JBHdVwAi3G7sSSdbsk8NfgA+LnUS88V/2EKaA0=