diff --git a/flags/flags.go b/flags/flags.go index 94bf2a4b3a..5056e78aec 100644 --- a/flags/flags.go +++ b/flags/flags.go @@ -103,6 +103,7 @@ type Flags struct { Metadata FlagsMetadata `embed:"" prefix:"metadata-"` LocalStore FlagsLocalStore `embed:"" prefix:"local-store-"` RemoteStore FlagsRemoteStore `embed:"" prefix:"remote-store-"` + OfflineStore FlagsOfflineStore `embed:"" prefix:"offline-store-"` Debuginfo FlagsDebuginfo `embed:"" prefix:"debuginfo-"` Symbolizer FlagsSymbolizer `embed:"" prefix:"symbolizer-"` OTLP FlagsOTLP `embed:"" prefix:"otlp-"` @@ -265,10 +266,15 @@ type FlagsMetadata struct { } // FlagsLocalStore provides local store configuration flags. +// TODO: remove/deprecate? type FlagsLocalStore struct { Directory string `help:"The local directory to store the profiling data."` } +type FlagsOfflineStore struct { + Directory string `help:"The local directory to store offline profiling data."` +} + // FlagsRemoteStore provides remote store configuration flags. type FlagsRemoteStore struct { Address string `help:"gRPC address to send profiles and symbols to."` diff --git a/go.mod b/go.mod index 741e3b9a06..554260efc6 100644 --- a/go.mod +++ b/go.mod @@ -9,12 +9,13 @@ require ( buf.build/gen/go/parca-dev/parca/protocolbuffers/go v1.34.2-20240709131200-45114c6d2c4d.2 buf.build/gen/go/prometheus/prometheus/protocolbuffers/go v1.34.2-20240704212942-bbf0a43bf797.2 github.com/alecthomas/kong v0.9.0 + github.com/apache/arrow/go/v14 v14.0.2 github.com/apache/arrow/go/v16 v16.1.0 github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2 github.com/cilium/ebpf v0.15.0 github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be github.com/containerd/containerd v1.7.20 - github.com/docker/docker v26.1.5+incompatible + github.com/docker/docker v27.1.1+incompatible github.com/elastic/go-freelru v0.13.0 github.com/gogo/protobuf v1.3.2 github.com/golang/snappy v0.0.4 @@ -25,6 +26,7 @@ require ( github.com/prometheus/client_golang v1.19.1 github.com/prometheus/common v0.54.0 github.com/prometheus/prometheus v0.53.1 + github.com/samborkent/uuidv7 v0.0.0-20231110121620-f2e19d87e48b github.com/sirupsen/logrus v1.9.3 github.com/stretchr/testify v1.9.0 github.com/tklauser/numcpus v0.8.0 @@ -73,7 +75,7 @@ require ( github.com/containerd/typeurl/v2 v2.1.1 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/distribution/reference v0.6.0 // indirect - github.com/docker/go-connections v0.4.0 // indirect + github.com/docker/go-connections v0.5.0 // indirect github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c // indirect github.com/docker/go-units v0.5.0 // indirect github.com/elastic/go-perf v0.0.0-20191212140718-9c656876f595 // indirect diff --git a/go.sum b/go.sum index c39b42ed26..26aff078ac 100644 --- a/go.sum +++ b/go.sum @@ -11,6 +11,8 @@ cloud.google.com/go v0.110.10 h1:LXy9GEO+timppncPIAZoOj3l58LIU9k+kn48AN7IO3Y= cloud.google.com/go/compute v1.25.1 h1:ZRpHJedLtTpKgr3RV1Fx23NuaAEN1Zfx9hw1u4aJdjU= cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc= cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= +dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= +dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU= github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20230306123547-8075edf89bb0 h1:59MxjQVfjXsBpLy+dbd2/ELV5ofnUkUZBvWSC85sheA= @@ -28,6 +30,8 @@ github.com/alecthomas/kong v0.9.0 h1:G5diXxc85KvoV2f0ZRVuMsi45IrBgx9zDNGNj165aPA github.com/alecthomas/kong v0.9.0/go.mod h1:Y47y5gKfHp1hDc7CH7OeXgLIpp+Q2m1Ni0L5s3bI8Os= github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc= github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= +github.com/apache/arrow/go/v14 v14.0.2 h1:N8OkaJEOfI3mEZt07BIkvo4sC6XDbL+48MBPWO5IONw= +github.com/apache/arrow/go/v14 v14.0.2/go.mod h1:u3fgh3EdgN/YQ8cVQRguVW3R+seMybFg8QBQ5LU+eBY= github.com/apache/arrow/go/v16 v16.1.0 h1:dwgfOya6s03CzH9JrjCBx6bkVb4yPD4ma3haj9p7FXI= github.com/apache/arrow/go/v16 v16.1.0/go.mod h1:9wnc9mn6vEDTRIm4+27pEjQpRKuTvBaessPoEXQzxWA= github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2 h1:7Ip0wMmLHLRJdrloDxZfhMm0xrLXZS8+COSu2bXmEQs= @@ -67,16 +71,18 @@ github.com/containerd/ttrpc v1.2.5 h1:IFckT1EFQoFBMG4c3sMdT8EP3/aKfumK1msY+Ze4oL github.com/containerd/ttrpc v1.2.5/go.mod h1:YCXHsb32f+Sq5/72xHubdiJRQY9inL4a4ZQrAbN1q9o= github.com/containerd/typeurl/v2 v2.1.1 h1:3Q4Pt7i8nYwy2KmQWIw2+1hTvwTE/6w9FqcttATPO/4= github.com/containerd/typeurl/v2 v2.1.1/go.mod h1:IDp2JFvbwZ31H8dQbEIY7sDl2L3o3HZj1hsSQlywkQ0= +github.com/cpuguy83/dockercfg v0.3.1 h1:/FpZ+JaygUR/lZP2NlFI2DVfrOEMAIKP5wWEJdoYe9E= +github.com/cpuguy83/dockercfg v0.3.1/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= -github.com/docker/docker v26.1.5+incompatible h1:NEAxTwEjxV6VbBMBoGG3zPqbiJosIApZjxlbrG9q3/g= -github.com/docker/docker v26.1.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= -github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/docker v27.1.1+incompatible h1:hO/M4MtV36kzKldqnA37IWhebRA+LnqqcqDja6kVaKY= +github.com/docker/docker v27.1.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= +github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8= github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= @@ -104,6 +110,8 @@ github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-openapi/jsonpointer v0.20.2 h1:mQc3nmndL8ZBzStEo3JYF8wzmeWffDH4VbXz58sAx6Q= github.com/go-openapi/jsonpointer v0.20.2/go.mod h1:bHen+N0u1KEO3YlmqOjTT9Adn1RfD91Ar825/PuiRVs= github.com/go-openapi/jsonreference v0.20.4 h1:bKlDxQxQJgwpUSgOENiMPzCTBVuc7vTdXSSgNeAhojU= @@ -185,6 +193,10 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= @@ -193,6 +205,8 @@ github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3N github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg= github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc= +github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= +github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vygl78= github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI= github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc= @@ -201,8 +215,8 @@ github.com/moby/sys/signal v0.7.0 h1:25RW3d5TnQEoKvRbEKUGay6DCQ46IxAVTT9CUMgmsSI github.com/moby/sys/signal v0.7.0/go.mod h1:GQ6ObYZfqacOwTtlXvcmh9A26dVRul/hbOZn88Kg8Tg= github.com/moby/sys/user v0.1.0 h1:WmZ93f5Ux6het5iituh9x2zAG7NFY9Aqi49jjE1PaQg= github.com/moby/sys/user v0.1.0/go.mod h1:fKJhFOnsCN6xZ5gSfbM6zaHGgDJMrqt9/reuj4T7MmU= -github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 h1:dcztxKSvZ4Id8iPpHERQBbIJfabdt4wUm5qy3wOL2Zc= -github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= +github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= +github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -226,8 +240,6 @@ github.com/opencontainers/runtime-spec v1.1.0 h1:HHUyrt9mwHUjtasSbXSMvs4cyFxh+Bl github.com/opencontainers/runtime-spec v1.1.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/selinux v1.11.0 h1:+5Zbo97w3Lbmb3PeqQtpmTkMwsW5nRI3YaLpt7tQ7oU= github.com/opencontainers/selinux v1.11.0/go.mod h1:E5dMC3VPuVvVHDYmi78qvhJp8+M586T4DlDRYpFkyec= -github.com/parca-dev/opentelemetry-ebpf-profiler v0.0.0-20240904132017-ba081e8ca369 h1:F+Pr+nY/Ob3pXwtl7g9lkxNoicdUmTq+jxuyG79yWaw= -github.com/parca-dev/opentelemetry-ebpf-profiler v0.0.0-20240904132017-ba081e8ca369/go.mod h1:GQVu1MAtVCPc3mW4Atj8YVUEPdXoC/vo/kp0lNpQZhw= github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ= github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -235,6 +247,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE= github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -248,6 +262,12 @@ github.com/prometheus/prometheus v0.53.1 h1:B0xu4VuVTKYrIuBMn/4YSUoIPYxs956qsOfc github.com/prometheus/prometheus v0.53.1/go.mod h1:RZDkzs+ShMBDkAPQkLEaLBXpjmDcjhNxU2drUVPgKUU= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/samborkent/uuidv7 v0.0.0-20231110121620-f2e19d87e48b h1:39v+thWy220bPAl5iP0p0b1s5DXmrtidMFRZqYsmEfI= +github.com/samborkent/uuidv7 v0.0.0-20231110121620-f2e19d87e48b/go.mod h1:Z46aLAe76cDDo+W1m5zVg+KeB+4P2+xWENVEFFzbBuQ= +github.com/shirou/gopsutil/v3 v3.23.12 h1:z90NtUkp3bMtmICZKpC4+WaknU1eXtp5vtbQ11DgpE4= +github.com/shirou/gopsutil/v3 v3.23.12/go.mod h1:1FrWgea594Jp7qmjHUUPlJDTPgcsb9mGnXDxavtikzM= +github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= +github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= @@ -262,12 +282,18 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/testcontainers/testcontainers-go v0.33.0 h1:zJS9PfXYT5O0ZFXM2xxXfk4J5UMw/kRiISng037Gxdw= +github.com/testcontainers/testcontainers-go v0.33.0/go.mod h1:W80YpTa8D5C3Yy16icheD01UTDu+LmXIA2Keo+jWtT8= +github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= +github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= github.com/tklauser/numcpus v0.8.0 h1:Mx4Wwe/FjZLeQsK/6kt2EOepwwSl7SmJrK5bV/dXYgY= github.com/tklauser/numcpus v0.8.0/go.mod h1:ZJZlAY+dmR4eut8epnzf0u/VwodKmryxR8txiloSqBE= github.com/xyproto/ainur v1.3.3 h1:DjbkZg7iNblH1abwfIQG2siI0z3LOyVuWEmCq2S9GKc= github.com/xyproto/ainur v1.3.3/go.mod h1:Sn5x2wSx2Q9RoZHIqJr927vVeM0oKwBl4lCMG+My/rk= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= +github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= github.com/zcalusic/sysinfo v1.1.0 h1:79Hqn8h4poVz6T57/4ezXbT5ZkZbZm7u1YU1C4paMyk= github.com/zcalusic/sysinfo v1.1.0/go.mod h1:NX+qYnWGtJVPV0yWldff9uppNKU4h40hJIRPf/pGLv4= github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ= @@ -309,6 +335,8 @@ golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= +golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY= golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI= diff --git a/main.go b/main.go index ccb819517e..cd83507c57 100644 --- a/main.go +++ b/main.go @@ -43,6 +43,7 @@ import ( "go.opentelemetry.io/otel/trace" "go.opentelemetry.io/otel/trace/noop" "golang.org/x/sys/unix" + "google.golang.org/grpc" "github.com/parca-dev/parca-agent/analytics" "github.com/parca-dev/parca-agent/config" @@ -160,13 +161,15 @@ func mainWithExitCode() flags.ExitCode { log.Errorf("failed to create tracing provider: %v", err) } } - - grpcConn, err := f.RemoteStore.WaitGrpcEndpoint(ctx, reg, tp) - if err != nil { - log.Errorf("failed to connect to server: %v", err) - return flags.ExitFailure + var grpcConn *grpc.ClientConn + if len(f.RemoteStore.Address) > 0 { + grpcConn, err = f.RemoteStore.WaitGrpcEndpoint(ctx, reg, tp) + if err != nil { + log.Errorf("failed to connect to server: %v", err) + return flags.ExitFailure + } + defer grpcConn.Close() } - defer grpcConn.Close() presentCores, err := numcpus.GetPresent() if err != nil { @@ -292,33 +295,51 @@ func mainWithExitCode() flags.ExitCode { intervals := times.New(5*time.Second, f.Profiling.Duration, f.Profiling.ProbabilisticInterval) times.StartRealtimeSync(mainCtx, f.ClockSyncInterval) + if grpcConn == nil && len(f.OfflineStore.Directory) == 0 || + grpcConn != nil && len(f.OfflineStore.Directory) > 0 { + return flags.Failure("Need to specify one of remote store or offline store") + } + + var rep otelreporter.Reporter // Network operations to CA start here // Connect to the collection agent - parcaReporter, err := reporter.New( - memory.DefaultAllocator, - profilestoregrpc.NewProfileStoreServiceClient(grpcConn), - debuginfogrpc.NewDebuginfoServiceClient(grpcConn), - externalLabels, - f.Profiling.Duration, - f.Debuginfo.Strip, - f.Debuginfo.UploadMaxParallel, - f.Debuginfo.UploadDisable, - int64(f.Profiling.CPUSamplingFrequency), - traceHandlerCacheSize, - f.Debuginfo.UploadQueueSize, - f.Debuginfo.TempDir, - f.Node, - relabelConfigs, - buildInfo.VcsRevision, - reg, - ) - if err != nil { - return flags.Failure("Failed to start reporting: %v", err) + if grpcConn != nil { + parcaReporter, err := reporter.New( + memory.DefaultAllocator, + profilestoregrpc.NewProfileStoreServiceClient(grpcConn), + debuginfogrpc.NewDebuginfoServiceClient(grpcConn), + externalLabels, + f.Profiling.Duration, + f.Debuginfo.Strip, + f.Debuginfo.UploadMaxParallel, + f.Debuginfo.UploadDisable, + int64(f.Profiling.CPUSamplingFrequency), + traceHandlerCacheSize, + f.Debuginfo.UploadQueueSize, + f.Debuginfo.TempDir, + f.Node, + relabelConfigs, + buildInfo.VcsRevision, + reg, + ) + if err != nil { + return flags.Failure("Failed to start reporting: %v", err) + } + otelmetrics.SetReporter(parcaReporter) + parcaReporter.Run(mainCtx) + rep = parcaReporter + } else if len(f.OfflineStore.Directory) > 0 { + offlineReporter, err := reporter.NewOfflineReporter( + f.OfflineStore.Directory, f, traceHandlerCacheSize, + buildInfo.VcsRevision) + if err != nil { + return flags.Failure("Failed to start reporting: %v", err) + } + offlineReporter.Run(mainCtx) + rep = offlineReporter + } else { + return flags.Failure("Either remote or Offline reporting must be enabled") } - otelmetrics.SetReporter(parcaReporter) - parcaReporter.Run(mainCtx) - var rep otelreporter.Reporter = parcaReporter - // Load the eBPF code and map definitions trc, err := tracer.NewTracer(mainCtx, &tracer.Config{ Reporter: rep, @@ -413,8 +434,11 @@ func mainWithExitCode() flags.ExitCode { log.Info("Stop processing ...") rep.Stop() - if err := grpcConn.Close(); err != nil { - log.Fatalf("Stopping connection of OTLP client client failed: %v", err) + // close is already called in a defer above? + if grpcConn != nil { + if err := grpcConn.Close(); err != nil { + log.Fatalf("Stopping connection of OTLP client client failed: %v", err) + } } log.Info("Exiting ...") diff --git a/reporter/arrow.go b/reporter/arrow.go index 8a9a1bd1ae..4eaf15e3fc 100644 --- a/reporter/arrow.go +++ b/reporter/arrow.go @@ -164,7 +164,7 @@ type LocationsWriter struct { FunctionStartLine *array.Int64Builder } -func (w *LocationsWriter) NewRecord(stacktraceIDs *array.Binary) arrow.Record { +func (w *LocationsWriter) NewRecord(stacktraceIDs arrow.Array) arrow.Record { numMappings := uint64(w.MappingFile.Len()) // Setting mapping start, limit and offset to 0 signals to the backend that diff --git a/reporter/parca_reporter.go b/reporter/parca_reporter.go index eebc042746..ca585de95a 100644 --- a/reporter/parca_reporter.go +++ b/reporter/parca_reporter.go @@ -160,9 +160,9 @@ func (r *ParcaReporter) ReportTraceEvent(trace *libpf.Trace, }) } - labelRetrievalResult := r.labelsForTID(meta.TID, meta.PID, meta.Comm) + labelsRR := r.labelsForTID(meta.TID, meta.PID, meta.Comm) - if !labelRetrievalResult.keep { + if !labelsRR.keep { log.Debugf("Skipping trace event for PID %d, as it was filtered out by relabeling", meta.PID) return } @@ -170,7 +170,12 @@ func (r *ParcaReporter) ReportTraceEvent(trace *libpf.Trace, r.sampleWriterMu.Lock() defer r.sampleWriterMu.Unlock() - for _, lbl := range labelRetrievalResult.labels { + r.reportTraceEventLocked(trace, meta, labelsRR) +} + +func (r *ParcaReporter) reportTraceEventLocked(trace *libpf.Trace, + meta *reporter.TraceEventMeta, labelsRR labelRetrievalResult) { + for _, lbl := range labelsRR.labels { r.sampleWriter.Label(lbl.Name).AppendString(lbl.Value) } @@ -716,139 +721,146 @@ func (r *ParcaReporter) buildSampleRecord(ctx context.Context) arrow.Record { func (r *ParcaReporter) buildStacktraceRecord(ctx context.Context, stacktraceIDs *array.Binary) (arrow.Record, error) { w := NewLocationsWriter(r.mem) for i := 0; i < stacktraceIDs.Len(); i++ { - isComplete := true - - traceHash, err := libpf.TraceHashFromBytes(stacktraceIDs.Value(i)) - if err != nil { + id := stacktraceIDs.Value(i) + if err := r.buildStacktraceRecordOne(w, id); err != nil { return nil, err } + } - traceInfo, exists := r.stacks.Get(traceHash) - if !exists { - w.LocationsList.Append(false) - w.IsComplete.Append(false) - continue - } + return w.NewRecord(stacktraceIDs), nil +} - // Walk every frame of the trace. - if len(traceInfo.frameTypes) == 0 { - w.LocationsList.Append(false) - } else { - w.LocationsList.Append(true) - } - for i := range traceInfo.frameTypes { - w.Locations.Append(true) - w.Address.Append(uint64(traceInfo.linenos[i])) - w.FrameType.AppendString(traceInfo.frameTypes[i].String()) - - switch frameKind := traceInfo.frameTypes[i]; frameKind { - case libpf.NativeFrame: - // As native frames are resolved in the backend, we use Mapping to - // report these frames. - - execInfo, exists := r.executables.Get(traceInfo.files[i]) - - if exists { - w.MappingFile.AppendString(execInfo.FileName) - - if execInfo.BuildID != "" { - w.MappingBuildID.AppendString(execInfo.BuildID) - } else { - w.MappingBuildID.AppendString(traceInfo.files[i].StringNoQuotes()) - } - } else { - // Next step: Select a proper default value, - // if the name of the executable is not known yet. - w.MappingFile.AppendString("UNKNOWN") - w.MappingBuildID.AppendNull() - isComplete = false - } - w.Lines.Append(false) - case libpf.KernelFrame: - w.MappingFile.AppendString("[kernel.kallsyms]") - w.MappingBuildID.AppendNull() +func (r *ParcaReporter) buildStacktraceRecordOne(w *LocationsWriter, id []byte) error { + traceHash, err := libpf.TraceHashFromBytes(id) + if err != nil { + return err + } + + traceInfo, exists := r.stacks.Get(traceHash) + if !exists { + w.LocationsList.Append(false) + w.IsComplete.Append(false) + return nil + } - // Reconstruct frameID - frameID := libpf.NewFrameID(traceInfo.files[i], traceInfo.linenos[i]) + // Walk every frame of the trace. + if len(traceInfo.frameTypes) == 0 { + w.LocationsList.Append(false) + } else { + w.LocationsList.Append(true) + } - symbol, exists := r.fallbackSymbols.Get(frameID) - if !exists { - // TODO: choose a proper default value if the kernel symbol was not - // reported yet. - symbol = "UNKNOWN" - isComplete = false - } + isComplete := true + for i := range traceInfo.frameTypes { + w.Locations.Append(true) + w.Address.Append(uint64(traceInfo.linenos[i])) + w.FrameType.AppendString(traceInfo.frameTypes[i].String()) + + switch frameKind := traceInfo.frameTypes[i]; frameKind { + case libpf.NativeFrame: + // As native frames are resolved in the backend, we use Mapping to + // report these frames. + + execInfo, exists := r.executables.Get(traceInfo.files[i]) - w.Lines.Append(true) - w.Line.Append(true) - w.LineNumber.Append(int64(0)) - w.FunctionName.AppendString(symbol) - w.FunctionSystemName.AppendString("") - w.FunctionFilename.AppendString("vmlinux") - w.FunctionStartLine.Append(int64(0)) - case libpf.AbortFrame: - // Next step: Figure out how the OTLP protocol - // could handle artificial frames, like AbortFrame, - // that are not originate from a native or interpreted - // program. - w.MappingFile.AppendString("agent-internal-error-frame") + if exists { + w.MappingFile.AppendString(execInfo.FileName) + + if execInfo.BuildID != "" { + w.MappingBuildID.AppendString(execInfo.BuildID) + } else { + w.MappingBuildID.AppendString(traceInfo.files[i].StringNoQuotes()) + } + } else { + // Next step: Select a proper default value, + // if the name of the executable is not known yet. + w.MappingFile.AppendString("UNKNOWN") w.MappingBuildID.AppendNull() - w.Lines.Append(true) - w.Line.Append(true) - w.LineNumber.Append(int64(0)) - w.FunctionName.AppendString("aborted") - w.FunctionSystemName.AppendString("") - w.FunctionFilename.AppendNull() - w.FunctionStartLine.Append(int64(0)) - default: - var ( - lineNumber int64 - functionName string - filePath string - ) + isComplete = false + } + w.Lines.Append(false) + case libpf.KernelFrame: + w.MappingFile.AppendString("[kernel.kallsyms]") + w.MappingBuildID.AppendNull() + + // Reconstruct frameID + frameID := libpf.NewFrameID(traceInfo.files[i], traceInfo.linenos[i]) + + symbol, exists := r.fallbackSymbols.Get(frameID) + if !exists { + // TODO: choose a proper default value if the kernel symbol was not + // reported yet. + symbol = "UNKNOWN" + isComplete = false + } - fileIDInfoLock, exists := r.frames.Get(traceInfo.files[i]) + w.Lines.Append(true) + w.Line.Append(true) + w.LineNumber.Append(int64(0)) + w.FunctionName.AppendString(symbol) + w.FunctionSystemName.AppendString("") + w.FunctionFilename.AppendString("vmlinux") + w.FunctionStartLine.Append(int64(0)) + case libpf.AbortFrame: + // Next step: Figure out how the OTLP protocol + // could handle artificial frames, like AbortFrame, + // that are not originate from a native or interpreted + // program. + w.MappingFile.AppendString("agent-internal-error-frame") + w.MappingBuildID.AppendNull() + w.Lines.Append(true) + w.Line.Append(true) + w.LineNumber.Append(int64(0)) + w.FunctionName.AppendString("aborted") + w.FunctionSystemName.AppendString("") + w.FunctionFilename.AppendNull() + w.FunctionStartLine.Append(int64(0)) + default: + var ( + lineNumber int64 + functionName string + filePath string + ) + + fileIDInfoLock, exists := r.frames.Get(traceInfo.files[i]) + if !exists { + // At this point, we do not have enough information for the + // frame. Therefore, we report a dummy entry and use the + // interpreter as filename. + functionName = "UNREPORTED" + filePath = "UNREPORTED" + isComplete = false + } else { + fileIDInfo := fileIDInfoLock.RLock() + si, exists := (*fileIDInfo)[traceInfo.linenos[i]] if !exists { - // At this point, we do not have enough information for the - // frame. Therefore, we report a dummy entry and use the - // interpreter as filename. - functionName = "UNREPORTED" - filePath = "UNREPORTED" + // At this point, we do not have enough information for + // the frame. Therefore, we report a dummy entry and + // use the interpreter as filename. To differentiate + // this case with the case where no information about + // the file ID is available at all, we use a different + // name for reported function. + functionName = "UNRESOLVED" + filePath = "UNRESOLVED" isComplete = false } else { - fileIDInfo := fileIDInfoLock.RLock() - si, exists := (*fileIDInfo)[traceInfo.linenos[i]] - if !exists { - // At this point, we do not have enough information for - // the frame. Therefore, we report a dummy entry and - // use the interpreter as filename. To differentiate - // this case with the case where no information about - // the file ID is available at all, we use a different - // name for reported function. - functionName = "UNRESOLVED" - filePath = "UNRESOLVED" - isComplete = false - } else { - lineNumber = int64(si.lineNumber) - functionName = si.functionName - filePath = si.filePath - } - fileIDInfoLock.RUnlock(&fileIDInfo) + lineNumber = int64(si.lineNumber) + functionName = si.functionName + filePath = si.filePath } - w.MappingFile.AppendString(frameKind.String()) - w.MappingBuildID.AppendNull() - w.Lines.Append(true) - w.Line.Append(true) - w.LineNumber.Append(lineNumber) - w.FunctionName.AppendString(functionName) - w.FunctionSystemName.AppendString("") - w.FunctionFilename.AppendString(filePath) - w.FunctionStartLine.Append(int64(0)) + fileIDInfoLock.RUnlock(&fileIDInfo) } + w.MappingFile.AppendString(frameKind.String()) + w.MappingBuildID.AppendNull() + w.Lines.Append(true) + w.Line.Append(true) + w.LineNumber.Append(lineNumber) + w.FunctionName.AppendString(functionName) + w.FunctionSystemName.AppendString("") + w.FunctionFilename.AppendString(filePath) + w.FunctionStartLine.Append(int64(0)) } - - w.IsComplete.Append(isComplete) } - - return w.NewRecord(stacktraceIDs), nil + w.IsComplete.Append(isComplete) + return nil }