RPC: continuous profiling for Python/JS/Go subprocesses#7558
Merged
jkschneider merged 1 commit intomainfrom May 4, 2026
Merged
RPC: continuous profiling for Python/JS/Go subprocesses#7558jkschneider merged 1 commit intomainfrom
jkschneider merged 1 commit intomainfrom
Conversation
Each language's RPC server now starts the Pyroscope SDK when PYROSCOPE_SERVER_ADDRESS is set in the environment, with PYROSCOPE_TAGS forwarded verbatim and a runtime=python/node/go tag added so flame graphs in a shared `modcli` Pyroscope application can be sliced by which subprocess produced them. Env vars propagate from the parent JVM via ProcessBuilder.environment() inheritance, so the saas-side CliProcessEnvContributor that already drives the JVM agent transparently reaches all four runtimes once these inits land. Python: pyroscope-io is a new optional dep ([profiling] extra) so local dev and CI without the package don't break — _init_pyroscope() warns and no-ops on ImportError. JS: @pyroscope/nodejs is a new optionalDependency so npm install doesn't fail when the binding's native components aren't available; initPyroscope() catches the require and warns. Go: github.com/grafana/pyroscope-go is a regular dep (Go has no optional deps; the SDK is small and pure-Go via stdlib pprof). initPyroscope() short-circuits on missing env so non-profiled deployments pay only one os.Getenv at startup. C# requires no rewrite-side change: CoreCLR loads the Pyroscope native profiler purely from CORECLR_ENABLE_PROFILING / CORECLR_PROFILER / CORECLR_PROFILER_PATH env vars, which the same saas-side contributor sets alongside PYROSCOPE_*.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Each language's RPC server now starts the Pyroscope SDK when
PYROSCOPE_SERVER_ADDRESSis set in the environment, withPYROSCOPE_TAGSforwarded verbatim and aruntime=python|node|gotag added so flame graphs in a sharedmodcliPyroscope application can be sliced by which subprocess produced them.The env-var propagation chain — recipe-worker JVM → modw → mod CLI JVM →
ProcessBuilderfor the RPC subprocess — works without code changes here becauseRewriteRpcProcess.run()callspb.environment().putAll(extras)rather than clearing inherited env. So once the saas-sideCliProcessEnvContributor(which today wires the JVM Pyroscope agent on the mod CLI) is extended to also setPYROSCOPE_SERVER_ADDRESS/PYROSCOPE_TAGS/PYROSCOPE_APPLICATION_NAME, all four runtimes profile under the samemodcliapp, separated by theruntimetag.Per-language notes
rewrite-python/rewrite/src/rewrite/rpc/server.py):_init_pyroscope()called frommain()after argparse.pyroscope-iois a new optional dep ([profiling]extra) so local dev and CI without the package don't break — the function warns and no-ops onImportError.rewrite-javascript/rewrite/src/rpc/server.ts):initPyroscope(logger)called frommain()right after the logger is constructed.@pyroscope/nodejsis a newoptionalDependenciesentry sonpm installdoesn't fail when the binding's native components aren't available;initPyroscopecatches therequireand warns.rewrite-go/cmd/rpc/main.go):initPyroscope()is the first line ofmain().github.com/grafana/pyroscope-go v1.2.8is a regular dep — Go has no optional-dep concept and the SDK is small and pure-Go (uses stdlib pprof under the hood). The function short-circuits on missing env so non-profiled deployments pay oneos.Getenvat startup.rewrite-csharp. CoreCLR loads the Pyroscope native profiler purely fromCORECLR_ENABLE_PROFILING/CORECLR_PROFILER/CORECLR_PROFILER_PATH, which the saas-side contributor will set alongsidePYROSCOPE_*.Test plan
python -c "import ast; ast.parse(open('.../server.py').read())"— parsestomliparse ofpyproject.toml— parses;[profiling]extra resolvesnpx tsc --noEmit -p tsconfig.test.json(rewrite-javascript) — cleango build ./cmd/rpc(rewrite-go) — cleango vet ./cmd/rpc(rewrite-go) — cleanapplication=modcliflame graphs in Grafana split byruntimetag (python, node, go, jvm). Requires the saas-sideCliProcessEnvContributorextension to land first.[profiling]extra installs cleanly in mod-cli-base's Python venv.optionalDependenciesdoesn't failnpm installon a clean container without the native binding present.