git.delta.rocks / jrsonnet / refs/commits / 3bff084b3bc8

difftreelog

feat display nix stacktraces

urvrmlrlYaroslav Bolyukin2025-10-26parent: #f5a8281.patch.diff
in: trunk

6 files changed

modifiedcmds/fleet/src/cmds/build_systems.rsdiffbeforeafterboth
118 {118 {
119 Ok(path) => path,119 Ok(path) => path,
120 Err(e) => {120 Err(e) => {
121 error!("failed to build host system closure: {:#}", e);121 error!("failed to build host system closure: {:?}", e);
122 return;122 return;
123 }123 }
124 };124 };
modifiedcrates/nix-eval/build.rsdiffbeforeafterboth
16 // Link nix C++ libraries for cxx16 // Link nix C++ libraries for cxx
17 for lib in &[17 for lib in &[
18 "nix-util",18 "nix-util",
19 "nix-util-c",
19 "nix-store",20 "nix-store",
20 "nix-expr",21 "nix-expr",
21 "nix-flake",22 "nix-flake",
3435
35 cxx_build::bridge("src/logging.rs")36 cxx_build::bridge("src/logging.rs")
36 .file("src/logging.cc")37 .file("src/logging.cc")
37 .std("c++20")38 .std("c++23")
38 .shared_flag(true)39 .shared_flag(true)
39 .compile("nix-eval-logging");40 .compile("nix-eval-logging");
40 cxx_build::bridge("src/lib.rs")41 cxx_build::bridge("src/lib.rs")
41 .file("src/lib.cc")42 .file("src/lib.cc")
42 .std("c++20")43 .std("c++23")
43 .shared_flag(true)44 .shared_flag(true)
44 .compile("nix-eval");45 .compile("nix-eval");
4546
modifiedcrates/nix-eval/src/lib.rsdiffbeforeafterboth
13pub use anyhow::Result;13pub use anyhow::Result;
14use tracing::instrument;14use tracing::instrument;
1515
16use self::logging::nix_logging_cxx;16use self::logging::{ErrorInfoBuilder, nix_logging_cxx};
17use self::nix_cxx::set_fetcher_setting;17use self::nix_cxx::set_fetcher_setting;
18use self::nix_raw::{18use self::nix_raw::{
19 BindingsBuilder as c_bindings_builder, EvalState as c_eval_state, GC_SUCCESS,19 BindingsBuilder as c_bindings_builder, EvalState as c_eval_state, GC_SUCCESS,
179 let code = unsafe { err_code(self.0) };179 let code = unsafe { err_code(self.0) };
180 NixErrorKind::from_int(code)180 NixErrorKind::from_int(code)
181 }181 }
182 fn error<'t>(&self) -> Option<Cow<'t, str>> {182 fn error<'t>(&self) -> Option<(Cow<'t, str>, Option<Box<ErrorInfoBuilder>>)> {
183 if let NixErrorKind::Generic = self.error_kind()? {183 if let NixErrorKind::Generic = self.error_kind()? {
184 let ei = unsafe { logging::nix_logging_cxx::extract_error_info(self.0) };
184 let mut err_out = String::new();185 let mut err_out = String::new();
185 unsafe {186 unsafe {
186 err_info_msg(187 err_info_msg(
190 (&raw mut err_out).cast(),191 (&raw mut err_out).cast(),
191 )192 )
192 };193 };
193 return Some(Cow::Owned(err_out));194 return Some((Cow::Owned(err_out), Some(ei)));
194 };195 };
195196
196 // TODO: Can throw error (resulting in panic) if unable to retrieve error. Should be able to resolve by passing context as a first argument,197 // TODO: Can throw error (resulting in panic) if unable to retrieve error. Should be able to resolve by passing context as a first argument,
197 // but it looks ugly198 // but it looks ugly
198 let str = unsafe { err_msg(null_mut(), self.0, null_mut()) };199 let str = unsafe { err_msg(null_mut(), self.0, null_mut()) };
199 Some(unsafe { CStr::from_ptr(str) }.to_string_lossy())200 Some((unsafe { CStr::from_ptr(str) }.to_string_lossy(), None))
200 }201 }
201 fn clean_err(&mut self) {202 fn clean_err(&mut self) {
202 unsafe {203 unsafe {
205 }206 }
206207
207 fn bail_if_error(&self) -> Result<()> {208 fn bail_if_error(&self) -> Result<()> {
208 if let Some(err) = self.error() {209 if let Some((err, stack)) = self.error() {
209 bail!("{err}");210 let mut e = Err(anyhow!("{err}"));
211 if let Some(stack) = stack {
212 for ele in stack.stack_frames {
213 e = e.with_context(|| {
214 if ele.pos.is_empty() {
215 ele.msg
216 } else {
217 format!("{} at {}", ele.msg, ele.pos)
218 }
219 })
220 }
221 }
222 return e.context("<nix frames>");
210 };223 };
211 Ok(())224 Ok(())
212 }225 }
modifiedcrates/nix-eval/src/logging.ccdiffbeforeafterboth
1#include "nix-eval/src/logging.rs"
2#include "logging.hh"1#include "logging.hh"
3#include <nix/util/logging.hh>2#include <nix/util/logging.hh>
3#include <nix/util/position.hh>
44
5using namespace nix;5using namespace nix;
6
7rust::Box<ErrorInfoBuilder> copy_error_info(const ErrorInfo &ei) {
8 auto s = ei.msg.str();
9 rust::Slice<const unsigned char> str(
10 reinterpret_cast<const unsigned char *>(s.data()), s.size());
11 auto b = new_error_info(ei.level, str);
12 if (!ei.traces.empty()) {
13 for (auto iter = ei.traces.rbegin(); iter != ei.traces.rend(); ++iter) {
14 auto msg = iter->hint.str();
15
16 rust::Slice<const unsigned char> msgv(
17 reinterpret_cast<const unsigned char *>(msg.data()), msg.size());
18
19 std::ostringstream oss;
20 if (iter->pos) {
21 iter->pos->print(oss, true);
22 }
23 std::string pos = oss.str();
24
25 rust::Slice<const unsigned char> posv(
26 reinterpret_cast<const unsigned char *>(pos.data()), pos.size());
27
28 b->push_stack_frame(msgv, posv);
29 }
30 }
31 return b;
32}
633
7struct TracingLogger : Logger {34struct TracingLogger : Logger {
8 TracingLogger() {}35 TracingLogger() {}
14 emit_log(lvl, str);41 emit_log(lvl, str);
15 }42 }
16 void logEI(const ErrorInfo &ei) override {43 void logEI(const ErrorInfo &ei) override {
17 auto s = ei.msg.str();44 auto b = copy_error_info(ei);
18 rust::Slice<const unsigned char> str(
19 reinterpret_cast<const unsigned char *>(s.data()), s.size());45 b->emit_error_info();
20 emit_log(ei.level, str);
21 }46 }
2247
23 void startActivity(ActivityId act, Verbosity lvl, ActivityType type,48 void startActivity(ActivityId act, Verbosity lvl, ActivityType type,
74 logger = std::make_unique<TracingLogger>();99 logger = std::make_unique<TracingLogger>();
75 // verbosity = lvlVomit;100 // verbosity = lvlVomit;
76}101}
102rust::Box<ErrorInfoBuilder>
103extract_error_info(const nix_c_context *read_context) {
104 return copy_error_info(read_context->info.value());
105}
77}106}
78107
modifiedcrates/nix-eval/src/logging.hhdiffbeforeafterboth
1#pragma once1#pragma once
2#include "nix-eval/src/logging.rs"
3#include "rust/cxx.h"
4#include <nix_api_util.h>
5#include <nix_api_util_internal.h>
6
7struct ErrorInfoBuilder;
28
3extern "C" {9extern "C" {
4void apply_tracing_logger();10void apply_tracing_logger();
11rust::Box<ErrorInfoBuilder> extract_error_info(const nix_c_context *ctx);
5}12}
613
modifiedcrates/nix-eval/src/logging.rsdiffbeforeafterboth
2use std::fmt::Arguments;2use std::fmt::Arguments;
3use std::sync::{LazyLock, Mutex};3use std::sync::{LazyLock, Mutex};
44
5use cxx::ExternType;
5use tracing::{6use tracing::{
6 Level, Span, debug, debug_span, error, error_span, info, info_span, trace, trace_span, warn,7 Level, Span, debug, debug_span, error, error_span, info, info_span, trace, trace_span, warn,
7 warn_span,8 warn_span,
535 out.output536 out.output
536}537}
538
539#[derive(Debug)]
540pub struct StackFrame {
541 pub msg: String,
542 pub pos: String,
543}
544
545#[derive(Debug)]
546pub struct ErrorInfoBuilder {
547 level: Level,
548 msg: String,
549 pub stack_frames: Vec<StackFrame>,
550}
551fn new_error_info(lvl: u32, v: &[u8]) -> Box<ErrorInfoBuilder> {
552 let verbosity = Verbosity::from_int(lvl);
553 let level: Level = verbosity.into();
554 let v = String::from_utf8_lossy(v);
555 Box::new(ErrorInfoBuilder {
556 level,
557 msg: v.to_string(),
558 stack_frames: Vec::new(),
559 })
560}
561impl ErrorInfoBuilder {
562 fn push_stack_frame(&mut self, v: &[u8], pos: &[u8]) {
563 let v = String::from_utf8_lossy(v);
564 let pos = String::from_utf8_lossy(pos);
565 self.stack_frames.push(StackFrame {
566 msg: v.to_string(),
567 pos: pos.to_string(),
568 });
569 }
570 fn emit_error_info(&mut self) {
571 error!("{}", self.msg);
572 for frame in &self.stack_frames {
573 error!(" {} at {}", frame.msg, frame.pos)
574 }
575 }
576}
537577
538#[cxx::bridge]578#[cxx::bridge]
539pub mod nix_logging_cxx {579pub mod nix_logging_cxx {
540 extern "Rust" {580 extern "Rust" {
541 type StartActivityBuilder;581 type StartActivityBuilder;
542 fn new_start_activity(activity_id: u64, lvl: u32, typ: u32) -> Box<StartActivityBuilder>;582 fn new_start_activity(activity_id: u64, lvl: u32, typ: u32) -> Box<StartActivityBuilder>;
543 fn add_int_field(&mut self, i: i32);583 fn add_int_field(&mut self, i: i32);
544 fn add_string_field(&mut self, v: &[u8]);584 fn add_string_field(&mut self, v: &[u8]);
545 fn emit(&mut self, parent: u64, s: &str);585 fn emit(&mut self, parent: u64, s: &str);
546 fn emit_result(&mut self, ty: u32);586 fn emit_result(&mut self, ty: u32);
547587 }
588 extern "Rust" {
589 type ErrorInfoBuilder;
590 fn new_error_info(lvl: u32, v: &[u8]) -> Box<ErrorInfoBuilder>;
591 fn push_stack_frame(&mut self, v: &[u8], pos: &[u8]);
592 fn emit_error_info(&mut self);
593 }
594 extern "Rust" {
548 fn emit_warn(v: &str);595 fn emit_warn(v: &str);
549 fn emit_stop(id: u64);596 fn emit_stop(id: u64);
550 fn emit_log(lvl: u32, v: &[u8]);597 fn emit_log(lvl: u32, v: &[u8]);
551 }598 }
552 unsafe extern "C++" {599 unsafe extern "C++" {
553 include!("nix-eval/src/logging.hh");600 include!("nix-eval/src/logging.hh");
601
602 type nix_c_context = crate::nix_raw::c_context;
554603
555 fn apply_tracing_logger();604 fn apply_tracing_logger();
605 unsafe fn extract_error_info(ctx: *const nix_c_context) -> Box<ErrorInfoBuilder>;
556 }606 }
557}607}
608
609unsafe impl ExternType for crate::nix_raw::c_context {
610 type Id = cxx::type_id!("nix_c_context");
611
612 type Kind = cxx::kind::Opaque;
613}
558614