difftreelog
feat display nix stacktraces
in: trunk
6 files changed
cmds/fleet/src/cmds/build_systems.rsdiffbeforeafterboth118 {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 };crates/nix-eval/build.rsdiffbeforeafterboth16 // Link nix C++ libraries for cxx16 // Link nix C++ libraries for cxx17 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",343535 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");4546crates/nix-eval/src/lib.rsdiffbeforeafterboth13pub use anyhow::Result;13pub use anyhow::Result;14use tracing::instrument;14use tracing::instrument;151516use 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 };195196196 // 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 ugly198 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 }206207207 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.msg216 } 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 }crates/nix-eval/src/logging.ccdiffbeforeafterboth1#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>445using namespace nix;5using namespace nix;67rust::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();1516 rust::Slice<const unsigned char> msgv(17 reinterpret_cast<const unsigned char *>(msg.data()), msg.size());1819 std::ostringstream oss;20 if (iter->pos) {21 iter->pos->print(oss, true);22 }23 std::string pos = oss.str();2425 rust::Slice<const unsigned char> posv(26 reinterpret_cast<const unsigned char *>(pos.data()), pos.size());2728 b->push_stack_frame(msgv, posv);29 }30 }31 return b;32}6337struct 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 }224723 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}78107crates/nix-eval/src/logging.hhdiffbeforeafterboth1#pragma once1#pragma once2#include "nix-eval/src/logging.rs"3#include "rust/cxx.h"4#include <nix_api_util.h>5#include <nix_api_util_internal.h>67struct ErrorInfoBuilder;283extern "C" {9extern "C" {4void apply_tracing_logger();10void apply_tracing_logger();11rust::Box<ErrorInfoBuilder> extract_error_info(const nix_c_context *ctx);5}12}613crates/nix-eval/src/logging.rsdiffbeforeafterboth2use std::fmt::Arguments;2use std::fmt::Arguments;3use std::sync::{LazyLock, Mutex};3use std::sync::{LazyLock, Mutex};445use 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.output536}537}538539#[derive(Debug)]540pub struct StackFrame {541 pub msg: String,542 pub pos: String,543}544545#[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}537577538#[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");601602 type nix_c_context = crate::nix_raw::c_context;554603555 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}608609unsafe impl ExternType for crate::nix_raw::c_context {610 type Id = cxx::type_id!("nix_c_context");611612 type Kind = cxx::kind::Opaque;613}558614