Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

stdenv: refactor nix logging functions #370742

Conversation

ConnorBaker
Copy link
Contributor

@ConnorBaker ConnorBaker commented Jan 3, 2025

Package maintainers frequently include echo commands in their phase expressions to provide breadcrumbs for debugging or information for troubleshooting. To try to standardize the logging format and avoid the need to remember to pipe the output from echo to stderr or NIX_LOG_FD, we have the log-level family of functions (nix*Log) and an unconditional log function, nixLog.

The nix*Log function family only prints to NIX_LOG_FD when the severity of the log message is at least the value of NIX_DEBUG. This should be the preferred logger.

The nixLog function logs unconditionally and is meant to be used to provide information about the status of some process or phase (e.g., log messages delimiting a series of substituteInPlace calls, or to notify about the progress of a setup hook). It should never be used by trivial builders or writers (see #328229).

These functions both make use of Bash's FUNCNAME shell variable to prefix the logged message with the caller (or the phase name, if the caller is an implicit hook), which is extremely useful when debugging failing phases.

I've been using this change to great success in an external repo containing a rewrite of our CUDA packaging: it is implemented here https://github.com/ConnorBaker/cuda-packages/tree/main/upstreamable-packages/nixLogWithLevelAndFunctionNameHook and an example of its use is here https://github.com/ConnorBaker/cuda-packages/blob/358e4a6a73f11042f4454e81918039e62ddfb261/cuda-packages/common/setupCudaHook/setup-cuda-hook.sh. I'm submitting it here because I believe it can help remove ad-hoc echo statements while also enriching our build logs.

Here's a snippet of the output I see when I build nccl:

cuda12.6-nccl> structuredAttrs is enabled
cuda12.6-nccl> source: installed nix loggers with level and function name functionality
cuda12.6-nccl> source: added noBrokenSymlinksInAllOutputs to postFixupHooks
cuda12.6-nccl> source: sourcing setup-cuda-hook.sh
cuda12.6-nccl> source: added setupCUDAPopulateArrays to preConfigureHooks
cuda12.6-nccl> source: added setupCUDAEnvironmentVariables to preConfigureHooks
cuda12.6-nccl> source: added setupCUDACmakeFlags to preConfigureHooks
cuda12.6-nccl> source: added propagateCudaLibraries to postFixupHooks
cuda12.6-nccl> source: added noBrokenSymlinksInAllOutputs to postFixupHooks
cuda12.6-nccl> Running phase: unpackPhase
cuda12.6-nccl> unpacking source archive /nix/store/p83r5nhn5i9fhrbprfpvdmbq1px99590-NVIDIA-nccl-v2.23.4-1
cuda12.6-nccl> source root is NVIDIA-nccl-v2.23.4-1
cuda12.6-nccl> Running phase: patchPhase
cuda12.6-nccl> patching script interpreter paths in ./src/device/generate.py
cuda12.6-nccl> ./src/device/generate.py: interpreter directive changed from "#!/usr/bin/env python3" to "/nix/store/c9m6yd8fg1flz2j5r4bif1ib5j20a0cy-python3-3.12.8/bin/python3"
cuda12.6-nccl> Running phase: updateAutotoolsGnuConfigScriptsPhase
cuda12.6-nccl> Running phase: configurePhase
cuda12.6-nccl> setupCUDAPopulateArrays: searching dependencies in pkgsBuildBuild for CUDA markers
cuda12.6-nccl> setupCUDAPopulateArrays: searching dependencies in pkgsBuildHost for CUDA markers
cuda12.6-nccl> setupCUDAPopulateArrays: found CUDA marker in /nix/store/acs9ccnlgkx6wmvjjh5kjiw3rly4sjas-cuda12.6-cuda_nvcc-12.6.85-dev from pkgsBuildHost
cuda12.6-nccl> setupCUDAPopulateArrays: found CUDA marker in /nix/store/91gl5axqklbh8hbcd9q8bpqq084r39s6-cuda12.6-cuda_nvcc-12.6.85-bin from pkgsBuildHost
cuda12.6-nccl> setupCUDAPopulateArrays: found CUDA marker in /nix/store/gswsylmapc3f4fb4njs6gsxvn2p8vv9m-cuda12.6-cuda_nvcc-12.6.85-include from pkgsBuildHost
cuda12.6-nccl> setupCUDAPopulateArrays: searching dependencies in pkgsBuildTarget for CUDA markers
cuda12.6-nccl> setupCUDAPopulateArrays: searching dependencies in pkgsHostHost for CUDA markers
cuda12.6-nccl> setupCUDAPopulateArrays: searching dependencies in pkgsHostTarget for CUDA markers
cuda12.6-nccl> setupCUDAPopulateArrays: found CUDA marker in /nix/store/9iyad3k0b1np3fslnbl6vh1blw1pzbqj-cuda12.6-cuda_cudart-12.6.77-dev from pkgsHostTarget
cuda12.6-nccl> setupCUDAPopulateArrays: found CUDA marker in /nix/store/00gyy9yf6n8rcxbi36miay91p3xgw93l-cuda12.6-cuda_cudart-12.6.77-include from pkgsHostTarget
cuda12.6-nccl> setupCUDAPopulateArrays: found CUDA marker in /nix/store/gswsylmapc3f4fb4njs6gsxvn2p8vv9m-cuda12.6-cuda_nvcc-12.6.85-include from pkgsHostTarget
cuda12.6-nccl> setupCUDAPopulateArrays: found CUDA marker in /nix/store/xnfs0swsk9laa35hnlpfhfi8jddbiqdy-cuda12.6-cuda_cccl-12.6.77-include from pkgsHostTarget
cuda12.6-nccl> setupCUDAPopulateArrays: found CUDA marker in /nix/store/hd7vskrjdi5kjmh2ir4ra6a34h5zzf1x-cuda12.6-cuda_cudart-12.6.77-lib from pkgsHostTarget
cuda12.6-nccl> setupCUDAPopulateArrays: found CUDA marker in /nix/store/70fj8bbfrx7rx9hrzsbqqw3z9mxdxp2j-cuda12.6-cuda_cudart-12.6.77-static from pkgsHostTarget
cuda12.6-nccl> setupCUDAPopulateArrays: found CUDA marker in /nix/store/gdrrsva6842fwgcq1sp1imknpsk2r1rg-cuda12.6-cuda_cudart-12.6.77-stubs from pkgsHostTarget
cuda12.6-nccl> setupCUDAPopulateArrays: found CUDA marker in /nix/store/acs9ccnlgkx6wmvjjh5kjiw3rly4sjas-cuda12.6-cuda_nvcc-12.6.85-dev from pkgsHostTarget
cuda12.6-nccl> setupCUDAPopulateArrays: found CUDA marker in /nix/store/91gl5axqklbh8hbcd9q8bpqq084r39s6-cuda12.6-cuda_nvcc-12.6.85-bin from pkgsHostTarget
cuda12.6-nccl> setupCUDAPopulateArrays: found CUDA marker in /nix/store/vx0h02f8jm3hr728rg2cjjdv8had7kp6-cuda12.6-cuda_cccl-12.6.77-dev from pkgsHostTarget
cuda12.6-nccl> setupCUDAPopulateArrays: searching dependencies in pkgsTargetTarget for CUDA markers
cuda12.6-nccl> setupCUDAEnvironmentVariables: added /nix/store/00gyy9yf6n8rcxbi36miay91p3xgw93l-cuda12.6-cuda_cudart-12.6.77-include to CUDAToolkit_ROOT
cuda12.6-nccl> setupCUDAEnvironmentVariables: added /nix/store/00gyy9yf6n8rcxbi36miay91p3xgw93l-cuda12.6-cuda_cudart-12.6.77-include/include to CUDAToolkit_INCLUDE_DIRS
cuda12.6-nccl> setupCUDAEnvironmentVariables: added /nix/store/acs9ccnlgkx6wmvjjh5kjiw3rly4sjas-cuda12.6-cuda_nvcc-12.6.85-dev to CUDAToolkit_ROOT
cuda12.6-nccl> setupCUDAEnvironmentVariables: added /nix/store/70fj8bbfrx7rx9hrzsbqqw3z9mxdxp2j-cuda12.6-cuda_cudart-12.6.77-static to CUDAToolkit_ROOT
cuda12.6-nccl> setupCUDAEnvironmentVariables: added /nix/store/9iyad3k0b1np3fslnbl6vh1blw1pzbqj-cuda12.6-cuda_cudart-12.6.77-dev to CUDAToolkit_ROOT
cuda12.6-nccl> setupCUDAEnvironmentVariables: added /nix/store/gswsylmapc3f4fb4njs6gsxvn2p8vv9m-cuda12.6-cuda_nvcc-12.6.85-include to CUDAToolkit_ROOT
cuda12.6-nccl> setupCUDAEnvironmentVariables: added /nix/store/gswsylmapc3f4fb4njs6gsxvn2p8vv9m-cuda12.6-cuda_nvcc-12.6.85-include/include to CUDAToolkit_INCLUDE_DIRS
cuda12.6-nccl> setupCUDAEnvironmentVariables: added /nix/store/gdrrsva6842fwgcq1sp1imknpsk2r1rg-cuda12.6-cuda_cudart-12.6.77-stubs to CUDAToolkit_ROOT
cuda12.6-nccl> setupCUDAEnvironmentVariables: added /nix/store/hd7vskrjdi5kjmh2ir4ra6a34h5zzf1x-cuda12.6-cuda_cudart-12.6.77-lib to CUDAToolkit_ROOT
cuda12.6-nccl> setupCUDAEnvironmentVariables: added /nix/store/vx0h02f8jm3hr728rg2cjjdv8had7kp6-cuda12.6-cuda_cccl-12.6.77-dev to CUDAToolkit_ROOT
cuda12.6-nccl> setupCUDAEnvironmentVariables: added /nix/store/xnfs0swsk9laa35hnlpfhfi8jddbiqdy-cuda12.6-cuda_cccl-12.6.77-include to CUDAToolkit_ROOT
cuda12.6-nccl> setupCUDAEnvironmentVariables: added /nix/store/xnfs0swsk9laa35hnlpfhfi8jddbiqdy-cuda12.6-cuda_cccl-12.6.77-include/include to CUDAToolkit_INCLUDE_DIRS
cuda12.6-nccl> setupCUDAEnvironmentVariables: added /nix/store/91gl5axqklbh8hbcd9q8bpqq084r39s6-cuda12.6-cuda_nvcc-12.6.85-bin to CUDAToolkit_ROOT
cuda12.6-nccl> setupCUDAEnvironmentVariables: set CUDAHOSTCXX to /nix/store/cxv2d1nnxjaqmzg9kaf64806prdcwi9v-gcc-wrapper-13.3.0/bin/c++
cuda12.6-nccl> setupCUDAEnvironmentVariables: set CUDAARCHS to 89
cuda12.6-nccl> setupCUDAEnvironmentVariables: appended -ccbin /nix/store/cxv2d1nnxjaqmzg9kaf64806prdcwi9v-gcc-wrapper-13.3.0/bin/c++ to NVCC_PREPEND_FLAGS
cuda12.6-nccl> setupCUDAEnvironmentVariables: set NVCC_CCBIN to /nix/store/cxv2d1nnxjaqmzg9kaf64806prdcwi9v-gcc-wrapper-13.3.0/bin/c++
cuda12.6-nccl> setupCUDAEnvironmentVariables: appended -Xfatbin=-compress-all to NVCC_PREPEND_FLAGS
cuda12.6-nccl> no configure script, doing nothing
cuda12.6-nccl> Running phase: buildPhase

Prior work

Future work

Ideally, we would have better integration with the Nix CLI such that using structured logging is enough for the CLI to filter messages.

Rebuilding derivations just to see logs with a higher level of verbosity is frustrating because it slows down development and introduces additional steps to get more visibility into failures. Instead, the Nix build log should be at full verbosity so that information is always available and the CLI should filter the output before display.

Things done

  • Built on platform(s)
    • x86_64-linux
    • aarch64-linux
    • x86_64-darwin
    • aarch64-darwin
  • For non-Linux: Is sandboxing enabled in nix.conf? (See Nix manual)
    • sandbox = relaxed
    • sandbox = true
  • Tested, as applicable:
  • Tested compilation of all packages that depend on this change using nix-shell -p nixpkgs-review --run "nixpkgs-review rev HEAD". Note: all changes have to be committed, also see nixpkgs-review usage
  • Tested basic functionality of all binary files (usually in ./result/bin/)
  • 25.05 Release Notes (or backporting 24.11 and 25.05 Release notes)
    • (Package updates) Added a release notes entry if the change is major or breaking
    • (Module updates) Added a release notes entry if the change is significant
    • (Module addition) Added a release notes entry if adding a new NixOS module
  • Fits CONTRIBUTING.md.

Add a 👍 reaction to pull requests you find important.

Copy link
Member

@RossComputerGuy RossComputerGuy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, I like how we can see where the calls are coming from with this.

@wegank wegank added 12.approvals: 1 This PR was reviewed and approved by one reputable person 12.approved-by: package-maintainer This PR was reviewed and approved by a maintainer listed in the package labels Jan 16, 2025
Copy link
Contributor

@philiptaron philiptaron left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few comments here and there, but nothing blocking.

pkgs/stdenv/generic/setup.sh Outdated Show resolved Hide resolved
callerName="${hookName:?}"
fi

# Use the function name of the caller's caller, since we should only every be invoked by nix*Log functions.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment is sort of duplicated with the above; I'd remove it. The thing that should replace it is a note that we could be using structured logging here.

I can't find any user-facing documentation of structured logging; the function that does it is here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had looked into using that previously, but correctly escaping JSON within Bash is very difficult. When I ignored that and tried to use simple text, I noticed it messed with the formatting of the output when --print-build-logs was passed to Nix. After that, I sort of shelved it. I'll add additional context to the PR description -- @emilazy had good ideas about how a better logging solution would function and I want to make a note of them, but it would require changes on the Nix side as well.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I definitely agree with all of that. It's bleeding edge at the moment, no doubt.

pkgs/stdenv/generic/setup.sh Outdated Show resolved Hide resolved
@@ -56,60 +56,100 @@ getAllOutputNames() {
fi
}

# All provided arguments are joined with a space, then prefixed by the name of the function which invoked `nixLog` (or
# the hook name if the caller was an implicit hook), then directed to $NIX_LOG_FD, if it's set.
nixLog() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nixLog used to accept other arguments. I deleted it (and there was no fallout, shockingly.)

I'm in favor of it returning.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't see other arguments accepted by nixLog prior to that PR; as it is implemented currently it accepts an arbitrary number of arguments but passes them as a single string to printf. I also wanted to avoid configurability and argument parsing.

@ConnorBaker
Copy link
Contributor Author

I'm going to merge this now, thank you for the feedback @philiptaron!

@ConnorBaker ConnorBaker merged commit 5ea2299 into NixOS:staging Jan 23, 2025
40 of 43 checks passed
@ConnorBaker ConnorBaker deleted the feat/nix-log-with-level-and-function-name branch January 23, 2025 08:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
6.topic: stdenv Standard environment 10.rebuild-darwin: 5001+ 10.rebuild-linux: 5001+ 12.approvals: 1 This PR was reviewed and approved by one reputable person 12.approved-by: package-maintainer This PR was reviewed and approved by a maintainer listed in the package
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants