From 5d533fdf3cd0a9ae62dd0bd09b7409344a01d989 Mon Sep 17 00:00:00 2001 From: Rudi Grinberg Date: Tue, 9 Dec 2025 21:25:22 +0000 Subject: [PATCH 1/2] dev Signed-off-by: Rudi Grinberg From e2fca6fbf0badd062c85e74a4e6832b4c0e000ea Mon Sep 17 00:00:00 2001 From: Rudi Grinberg Date: Wed, 10 Dec 2025 23:51:15 +0000 Subject: [PATCH 2/2] feature: structured logging Logging messages now accept a payload of the form: [(string * Dyn.t) list] in addition to the message. They are also replicated to the trace file where they structure is preserved. Signed-off-by: Rudi Grinberg --- bin/common.ml | 97 +++++------ bin/common.mli | 1 - bin/monitor.ml | 5 +- bin/pkg/lock.ml | 8 +- bin/scheduler.ml | 6 +- otherlibs/stdune/src/log.ml | 160 +++++++++++------- otherlibs/stdune/src/log.mli | 39 +++-- src/dune_cache/shared.ml | 25 ++- src/dune_config_file/dune_config_file.ml | 2 +- src/dune_config_file/dune_config_file.mli | 1 + src/dune_console/dune_console.ml | 15 +- src/dune_engine/build_system.ml | 9 +- src/dune_engine/fs_memo.ml | 6 +- src/dune_engine/scheduler.ml | 14 +- src/dune_pkg/lock_dir.ml | 11 +- src/dune_pkg/rev_store.ml | 16 +- src/dune_rpc_server/dune_rpc_server.ml | 13 +- src/dune_rules/context.ml | 5 +- src/dune_rules/odoc_new.ml | 64 +++---- src/dune_rules/pkg_toolchain.ml | 2 +- .../dune_threaded_console.ml | 9 +- src/dune_trace/category.ml | 4 + src/dune_trace/category.mli | 1 + src/dune_trace/dune_trace.mli | 2 + src/dune_trace/event.ml | 14 ++ src/dune_util/persistent.ml | 12 +- .../test-cases/cmdline/profile.t | 52 ++++-- .../test-cases/corrupt-persistent.t | 10 +- .../test-cases/custom-build-dir.t/run.t | 2 - .../dune-init-proj-no-spurious-build-dir.t | 6 +- .../test-cases/dune-init/dune-init.t/run.t | 9 - .../test-cases/exec/exec-cmd.t/run.t | 1 + .../test-cases/pkg/log-solution.t | 54 +++--- .../portable-lockdirs-partial-solve.t | 38 +++-- .../test-cases/promote/promote-variables.t | 1 - .../test-cases/trace-file.t/dune | 3 +- 36 files changed, 406 insertions(+), 311 deletions(-) diff --git a/bin/common.ml b/bin/common.ml index 27994a572b0..61fe8e62319 100644 --- a/bin/common.ml +++ b/bin/common.ml @@ -645,7 +645,6 @@ module Builder = struct ; stats_trace_file : string option ; allow_builds : bool ; default_root_is_cwd : bool - ; log_file : Log.File.t } let root t = t.root @@ -653,7 +652,7 @@ module Builder = struct let forbid_builds t = { t with allow_builds = false; no_print_directory = true } let default_root_is_cwd t = t.default_root_is_cwd let set_default_root_is_cwd t x = { t with default_root_is_cwd = x } - let disable_log_file t = { t with log_file = No_log_file } + let disable_log_file t = { t with stats_trace_file = None } let set_promote t v = { t with promote = Some v } let default_target t = t.default_target @@ -892,7 +891,7 @@ module Builder = struct and+ stats_trace_file = Arg.( value - & opt (some string) None + & opt (some string) (Some "_build/trace.json") & info [ "trace-file" ] ~docs @@ -1067,7 +1066,6 @@ module Builder = struct ; stats_trace_file ; allow_builds = true ; default_root_is_cwd = false - ; log_file = Default } ;; @@ -1112,7 +1110,6 @@ module Builder = struct ; stats_trace_file ; allow_builds ; default_root_is_cwd - ; log_file } = Bool.equal t.debug_dep_path debug_dep_path @@ -1152,7 +1149,6 @@ module Builder = struct && Option.equal String.equal t.stats_trace_file stats_trace_file && Bool.equal t.allow_builds allow_builds && Bool.equal t.default_root_is_cwd default_root_is_cwd - && Log.File.equal t.log_file log_file ;; end @@ -1161,7 +1157,6 @@ type t = ; root : Workspace_root.t ; rpc : [ `Allow of Dune_lang.Dep_conf.t Dune_rpc_impl.Server.t Lazy.t | `Forbid_builds ] - ; stats : Dune_trace.Out.t option } let capture_outputs t = t.builder.capture_outputs @@ -1182,7 +1177,6 @@ let rpc t = ;; let watch_exclusions t = t.builder.watch_exclusions -let stats t = t.stats (* To avoid needless recompilations under Windows, where the case of [Sys.getcwd] can vary between different invocations of [dune], normalize to @@ -1251,33 +1245,6 @@ let print_entering_message c = (* CR-someday rleshchinskiy: The split between `build` and `init` seems quite arbitrary, we should probably refactor that at some point. *) let build (root : Workspace_root.t) (builder : Builder.t) = - let stats = - Option.map builder.stats_trace_file ~f:(fun f -> - let cats = - match Sys.getenv_opt "DUNE_TRACE" with - | None -> - Dune_trace.Category. - [ Sandbox - ; Persistent - ; Process - ; Rules - ; Pkg - ; Promote - ; Build - ; File_watcher - ; Diagnostics - ] - | Some s -> - String.split ~on:',' s - |> List.map ~f:(fun x -> - match Dune_trace.Category.of_string x with - | Some s -> s - | None -> User_error.raise [ Pp.textf "unrecognized trace category %S" x ]) - in - let stats = Dune_trace.Out.create cats (Out (open_out f)) in - Dune_trace.set_global stats; - stats) - in let rpc = if builder.allow_builds then @@ -1302,7 +1269,7 @@ let build (root : Workspace_root.t) (builder : Builder.t) = else `Forbid_builds in if builder.print_metrics then Dune_metrics.enable (); - { builder; root; rpc; stats } + { builder; root; rpc } ;; let maybe_init_cache (cache_config : Dune_cache.Config.t) = @@ -1327,9 +1294,40 @@ let init_with_root ~(root : Workspace_root.t) (builder : Builder.t) = if c.root.dir <> Filename.current_dir_name then Sys.chdir c.root.dir; Path.set_root (normalize_path (Path.External.cwd ())); Path.Build.set_build_dir (Path.Outside_build_dir.of_string c.builder.build_dir); - (* Once we have the build directory set, initialise the logging. We can't do - this earlier, because the build log typically goes into [_build/log]. *) - Log.init builder.log_file; + let () = + match builder.stats_trace_file with + | None -> Log.init No_log_file + | Some stats -> + let trace = Path.of_filename_relative_to_initial_cwd stats in + let cats = + match Sys.getenv_opt "DUNE_TRACE" with + | None -> + Dune_trace.Category. + [ Config + ; Sandbox + ; Persistent + ; Process + ; Rules + ; Pkg + ; Promote + ; Build + ; Log + ; File_watcher + ; Diagnostics + ] + | Some s -> + String.split ~on:',' s + |> List.map ~f:(fun x -> + match Dune_trace.Category.of_string x with + | Some s -> s + | None -> User_error.raise [ Pp.textf "unrecognized trace category %S" x ]) + in + Path.parent trace |> Option.iter ~f:Path.mkdir_p; + let stats = Dune_trace.Out.create cats (Out (open_out (Path.to_string trace))) in + Dune_trace.set_global stats; + Log.init + (Redirect (fun w -> Dune_trace.emit Log (fun () -> Dune_trace.Event.log w))) + in (* We need to print this before reading the workspace file, so that the editor can interpret errors in the workspace file. *) print_entering_message c; @@ -1365,17 +1363,16 @@ let init_with_root ~(root : Workspace_root.t) (builder : Builder.t) = } in Log.info - [ Pp.textf - "Shared cache: %s" - (Dune_config.Cache.Toggle.to_string config.cache_enabled) - ]; + "Shared cache enabled" + [ "cache_enabled", Dune_config.Cache.Toggle.to_dyn config.cache_enabled ]; Log.info - [ Pp.textf - "Shared build cache location: %s" - (Path.to_string (Lazy.force Dune_cache_storage.Layout.build_cache_dir)) + "Shared cache location" + [ ( "root_dir" + , Dyn.string (Path.to_string (Lazy.force Dune_cache_storage.Layout.build_cache_dir)) + ) ]; Dune_rules.Main.init - ~stats:c.stats + ~stats:(Dune_trace.global ()) ~sandboxing_preference:config.sandboxing_preference ~cache_config:(maybe_init_cache cache_config) ~cache_debug_flags:c.builder.cache_debug_flags @@ -1406,10 +1403,8 @@ let init_with_root ~(root : Workspace_root.t) (builder : Builder.t) = | Disabled | Enabled_except_user_rules -> false | Enabled -> true); Log.info - [ Pp.textf - "Workspace root: %s" - (Path.to_absolute_filename Path.root |> String.maybe_quoted) - ]; + "Workspace root" + [ "root", Dyn.string (Path.to_absolute_filename Path.root |> String.maybe_quoted) ]; Dune_console.separate_messages c.builder.separate_error_messages; Dune_trace.always_emit (Dune_trace.Event.config diff --git a/bin/common.mli b/bin/common.mli index c0f4c05f7f0..1e28a0aee58 100644 --- a/bin/common.mli +++ b/bin/common.mli @@ -17,7 +17,6 @@ val rpc ] val watch_exclusions : t -> string list -val stats : t -> Dune_trace.Out.t option val print_metrics : t -> bool val dump_memo_graph_file : t -> Path.External.t option val dump_memo_graph_format : t -> Dune_graph.Graph.File_format.t diff --git a/bin/monitor.ml b/bin/monitor.ml index e962fe47a92..91ca8e81bf2 100644 --- a/bin/monitor.ml +++ b/bin/monitor.ml @@ -276,12 +276,11 @@ let command = in let builder = Common.Builder.forbid_builds builder in let builder = Common.Builder.disable_log_file builder in - let common, config = Common.init builder in - let stats = Common.stats common in + let _common, config = Common.init builder in let config = Dune_config.for_scheduler config - stats + (Dune_trace.global ()) ~print_ctrl_c_warning:true ~watch_exclusions:[] in diff --git a/bin/pkg/lock.ml b/bin/pkg/lock.ml index a61871b1be8..e9d48fae32d 100644 --- a/bin/pkg/lock.ml +++ b/bin/pkg/lock.ml @@ -383,7 +383,9 @@ let solve_lock_dir | `All_error messages -> Error messages | `All_ok solver_result -> Ok (solver_result, []) | `Partial (solver_result, errors) -> - Log.info @@ pp_solve_errors_by_platforms errors; + Log.info + "Solver found partial solution" + [ "error_count", Dyn.int (List.length errors) ]; let all_platforms = List.concat_map errors ~f:snd |> List.sort_uniq ~compare:Solver_env.compare in @@ -402,8 +404,8 @@ let solve_lock_dir ; Pp.nop ; Pp.box @@ Pp.text - "See the log or run with --verbose for more details. Configure \ - platforms to solve for in the dune-workspace file." + "See the trace file with --trace-file for more details. \ + Configure platforms to solve for in the dune-workspace file." ] ] ) in diff --git a/bin/scheduler.ml b/bin/scheduler.ml index bd85af164cf..1bea3b382fc 100644 --- a/bin/scheduler.ml +++ b/bin/scheduler.ml @@ -80,12 +80,11 @@ let no_build_no_rpc ~config:dune_config f = ;; let go_without_rpc_server ~(common : Common.t) ~config:dune_config f = - let stats = Common.stats common in let config = let watch_exclusions = Common.watch_exclusions common in Dune_config.for_scheduler dune_config - stats + (Dune_trace.global ()) ~print_ctrl_c_warning:true ~watch_exclusions in @@ -112,12 +111,11 @@ let go_with_rpc_server_and_console_status_reporting | `Allow server -> rpc server | `Forbid_builds -> Code_error.raise "rpc must be enabled in polling mode" [] in - let stats = Common.stats common in let config = let watch_exclusions = Common.watch_exclusions common in Dune_config.for_scheduler dune_config - stats + (Dune_trace.global ()) ~print_ctrl_c_warning:true ~watch_exclusions in diff --git a/otherlibs/stdune/src/log.ml b/otherlibs/stdune/src/log.ml index 87f04051908..a00528ac3d7 100644 --- a/otherlibs/stdune/src/log.ml +++ b/otherlibs/stdune/src/log.ml @@ -1,86 +1,124 @@ +let sprintf = Printf.sprintf + +module Message = struct + type level = + [ `Warn + | `Info + | `Verbose + ] + + let string_of_level = function + | `Warn -> "Warn" + | `Info -> "Info" + | `Verbose -> "Verbose" + ;; + + type t = + { level : level + ; message : string + ; args : (string * Dyn.t) list + } + + let ocamlparam () = + { level = `Info + ; message = "ocamlparam" + ; args = + [ ( "OCAMLPARAM" + , Dyn.string + (match Env.get Env.initial "OCAMLPARAM" with + | Some s -> Printf.sprintf "%S" s + | None -> "unset") ) + ] + } + ;; + + let create level message args = { level; message; args } +end + module File = struct type t = - | Default + | Redirect of (Message.t -> unit) | No_log_file | Stderr - - let equal a b = - match a, b with - | Default, Default | No_log_file, No_log_file | Stderr, Stderr -> true - | _, _ -> false - ;; + | Both of t * t end -type real = { oc : out_channel option } +type real = + | No_log_file + | Redirect of (Message.t -> unit) + | Output of out_channel + | Both of real * real let t = Fdecl.create Dyn.opaque let verbose = ref false -let init (file : File.t) = - let oc = - match file with - | No_log_file -> None - | Stderr -> Some stderr - | Default -> - Path.ensure_build_dir_exists (); - Some (Io.open_out (Path.relative Path.build_dir "log")) - in - Option.iter oc ~f:(fun oc -> - Printf.fprintf - oc - "# %s\n# OCAMLPARAM: %s\n%!" - (String.quote_list_for_shell (Array.to_list Sys.argv)) - (match Env.get Env.initial "OCAMLPARAM" with - | Some s -> Printf.sprintf "%S" s - | None -> "unset")); - Fdecl.set t (Some { oc }) +let format_args args = + List.map args ~f:(fun (k, v) -> Printf.sprintf "%s: %s" k (Dyn.to_string v)) + |> String.concat ~sep:" " ;; -let t () = Fdecl.get t +let write_oc oc { Message.level; message; args } = + output_string + oc + (sprintf "%s %s | %s\n" (Message.string_of_level level) message (format_args args)) +;; -let log_oc oc msg = - let s = Format.asprintf "%a@?" Pp.to_fmt (User_message.pp msg) in - List.iter (String.split_lines s) ~f:(function - | "" -> output_string oc "#\n" - | s -> Printf.fprintf oc "# %s\n" s); - flush oc +let rec emit (t : real) (message : Message.t) = + match t with + | No_log_file -> () + | Redirect w -> w message + | Output oc -> write_oc oc message + | Both (x, y) -> + emit x message; + emit y message ;; -let log msg = - match t () with - | None -> () - | Some { oc; _ } -> - Option.iter oc ~f:(fun oc -> User_message.make (msg ()) |> log_oc oc) +let init (dst : File.t) = + let rec make (dst : File.t) = + match dst with + | No_log_file -> No_log_file + | Stderr -> Output stderr + | Redirect w -> Redirect w + | Both (x, y) -> Both (make x, make y) + in + Fdecl.set t (make dst); + emit (Fdecl.get t) (Message.ocamlparam ()) ;; +let t () = Fdecl.get t let forward_verbose = Fdecl.create Dyn.opaque let set_forward_verbose = Fdecl.set forward_verbose +let log f = emit (t ()) (f ()) -let info_user_message msg = - match t () with - | None -> () - | Some { oc; _ } -> - Option.iter oc ~f:(fun oc -> log_oc oc msg); - if !verbose then (Fdecl.get forward_verbose) msg +let info message args = + emit (t ()) { Message.level = `Info; message; args }; + if !verbose then (Fdecl.get forward_verbose) message args ;; -let info paragraphs = info_user_message (User_message.make paragraphs) +let warn message args = info ("Warning: " ^ message) args let command ~command_line ~output ~exit_status = - match t () with - | None | Some { oc = None; _ } -> () - | Some { oc = Some oc; _ } -> - Printf.fprintf oc "$ %s\n" (Ansi_color.strip command_line); - List.iter (String.split_lines output) ~f:(fun s -> - match Ansi_color.strip s with - | "" -> output_string oc ">\n" - | s -> Printf.fprintf oc "> %s\n" s); - (match (exit_status : Unix.process_status) with - | WEXITED 0 -> () - | WEXITED n -> Printf.fprintf oc "[%d]\n" n - | WSIGNALED n -> - let name = Signal.of_int n |> Signal.name in - Printf.fprintf oc "[got signal %s]\n" name - | WSTOPPED _ -> assert false); - flush oc + if !verbose + then ( + let command_line = Ansi_color.strip command_line in + let exit_status = + match (exit_status : Unix.process_status) with + | WEXITED n -> Printf.sprintf "[%d]" n + | WSIGNALED n -> + let name = Signal.of_int n |> Signal.name in + Printf.sprintf "[got signal %s]" name + | WSTOPPED _ -> assert false + in + emit + (t ()) + { Message.level = `Info + ; message = "command" + ; args = + [ "command_line", Dyn.string command_line + ; "outupt", Dyn.string output + ; "exit_status", Dyn.string exit_status + ] + }) ;; + +let verbose_message m args = if !verbose then info m args diff --git a/otherlibs/stdune/src/log.mli b/otherlibs/stdune/src/log.mli index 1b20228d9c2..51e373a3345 100644 --- a/otherlibs/stdune/src/log.mli +++ b/otherlibs/stdune/src/log.mli @@ -1,31 +1,38 @@ (** Log file *) +module Message : sig + type level = + [ `Warn + | `Info + | `Verbose + ] + + type t = + { level : level + ; message : string + ; args : (string * Dyn.t) list + } + + val create : level -> string -> (string * Dyn.t) list -> t +end + module File : sig type t = - | Default + | Redirect of (Message.t -> unit) | No_log_file | Stderr - - val equal : t -> t -> bool + | Both of t * t end (** Initialise the log file *) val init : File.t -> unit (** Print the message only the log file (despite verbose mode) if it's set *) -val log : (unit -> User_message.Style.t Pp.t list) -> unit - -val set_forward_verbose : (User_message.t -> unit) -> unit - -(** Print an informative message in the log *) -val info_user_message : User_message.t -> unit +val log : (unit -> Message.t) -> unit -(** [info paragraphs] is a short-hand for: - - {[ - info_user_message (User_message.make paragraphs) - ]} *) -val info : User_message.Style.t Pp.t list -> unit +val set_forward_verbose : (string -> (string * Dyn.t) list -> unit) -> unit +val info : string -> (string * Dyn.t) list -> unit +val warn : string -> (string * Dyn.t) list -> unit (** Print an executed command in the log *) val command @@ -34,5 +41,7 @@ val command -> exit_status:Unix.process_status -> unit +val verbose_message : string -> (string * Dyn.t) list -> unit + (** Whether we are running in verbose mode *) val verbose : bool ref diff --git a/src/dune_cache/shared.ml b/src/dune_cache/shared.ml index 9b64d258d18..5cd0cab90bd 100644 --- a/src/dune_cache/shared.ml +++ b/src/dune_cache/shared.ml @@ -59,7 +59,8 @@ struct we're also printing successes, but it can be useful to see successes too if the goal is to understand when and how the file in the build directory appeared *) - if debug_shared_cache then Log.info [ Pp.textf "cache restore success %s" (key ()) ]; + if debug_shared_cache + then Log.info "cache restore success" [ "key", Dyn.string (key ()) ]; Hit_or_miss.Hit artifacts | Not_found_in_cache -> Hit_or_miss.Miss Miss_reason.Not_found_in_cache | Error exn -> Miss (Error (Printexc.to_string exn)) @@ -147,33 +148,31 @@ struct >>= (function | Stored targets_and_digests -> let+ () = upload ~rule_digest in - Log.info [ Pp.textf "cache store success [%s]" hex ]; + Log.info "cache store success" [ "hex", Dyn.string hex ]; update_cached_digests ~targets_and_digests; Some targets_and_digests | Already_present targets_and_digests -> - Log.info [ Pp.textf "cache store skipped [%s]: already present" hex ]; + Log.info "cache store skipped: already present" [ "hex", Dyn.string hex ]; update_cached_digests ~targets_and_digests; Fiber.return (Some targets_and_digests) | Error (Unix.Unix_error (Unix.EXDEV, "link", file)) -> (* We cannot hardlink across partitions so we kindly let the user know that they should use copy cache instead. *) Log.info - [ Pp.concat - [ Pp.textf "cache store error [%s]:" hex - ; Pp.space - ; Pp.textf - "cannot link %s between file systems. Use (cache-storage-mode copy) \ - instead." - file - ] + "cache store error" + [ "hex", Dyn.string hex + ; "file", Dyn.string file + ; "reason", Dyn.string "cannot link between file systems" ]; Fiber.return None | Error exn -> - Log.info [ pp_error (Printexc.to_string exn) ]; + Log.info "cache store error" [ "error", Dyn.string (Printexc.to_string exn) ]; Fiber.return None | Will_not_store_due_to_non_determinism sexp -> (* CR-someday amokhov: We should systematically log all warnings. *) - Log.info [ pp_error (Sexp.to_string sexp) ]; + Log.info + "cache store non-deterministic" + [ "sexp", Dyn.string (Sexp.to_string sexp) ]; User_warning.emit [ pp_error (Sexp.to_string sexp) ]; Fiber.return None) ;; diff --git a/src/dune_config_file/dune_config_file.ml b/src/dune_config_file/dune_config_file.ml index 9b015628fb5..1ab7f128059 100644 --- a/src/dune_config_file/dune_config_file.ml +++ b/src/dune_config_file/dune_config_file.ml @@ -715,7 +715,7 @@ module Dune_config = struct | Fixed i -> i | Auto -> let n = Lazy.force auto_concurrency in - Log.info [ Pp.textf "Auto-detected concurrency: %d" n ]; + Log.info "Auto-detected concurrency" [ "concurrency", Dyn.int n ]; n in (Dune_engine.Clflags.display diff --git a/src/dune_config_file/dune_config_file.mli b/src/dune_config_file/dune_config_file.mli index 559954e450d..d4795948c23 100644 --- a/src/dune_config_file/dune_config_file.mli +++ b/src/dune_config_file/dune_config_file.mli @@ -43,6 +43,7 @@ module Dune_config : sig -> t Dune_lang.Decoder.t val to_string : t -> string + val to_dyn : t -> Dyn.t end module Storage_mode : sig diff --git a/src/dune_console/dune_console.ml b/src/dune_console/dune_console.ml index 199a05cec82..eeb12581197 100644 --- a/src/dune_console/dune_console.ml +++ b/src/dune_console/dune_console.ml @@ -170,4 +170,17 @@ module Status_line = struct end let () = User_warning.set_reporter print_user_message -let () = Log.set_forward_verbose print_user_message + +let () = + Log.set_forward_verbose (fun msg args -> + let formatted_args = + List.map args ~f:(fun (k, v) -> Printf.sprintf "%s: %s" k (Dyn.to_string v)) + |> String.concat ~sep:" " + in + let full_msg = + if String.is_empty formatted_args + then msg + else Printf.sprintf "%s %s" msg formatted_args + in + print [ Pp.verbatim full_msg ]) +;; diff --git a/src/dune_engine/build_system.ml b/src/dune_engine/build_system.ml index 34bc4e66edf..2cc69d055e8 100644 --- a/src/dune_engine/build_system.ml +++ b/src/dune_engine/build_system.ml @@ -591,11 +591,10 @@ end = struct in anyway. *) remove_target_dir path | Error exn -> - Log.info - [ Pp.textf - "Error while removing target %s: %s" - (Path.Build.to_string path) - (Printexc.to_string exn) + Log.warn + "Error while removing target" + [ "path", Dyn.string (Path.Build.to_string path) + ; "error", Dyn.string (Printexc.to_string exn) ] in Targets.Validated.iter diff --git a/src/dune_engine/fs_memo.ml b/src/dune_engine/fs_memo.ml index 166ee424b55..96e31d8619d 100644 --- a/src/dune_engine/fs_memo.ml +++ b/src/dune_engine/fs_memo.ml @@ -83,10 +83,8 @@ end = struct | Ok () -> () | Error `Does_not_exist -> Log.info - [ Pp.textf - "Attempted to add watch to non-existent directory %s." - (Path.to_string containing_dir) - ]); + "Attempted to add watch to non-existent directory" + [ "path", Dyn.string (Path.to_string containing_dir) ]); (match Dune_file_watcher.add_watch watcher path with | Error `Does_not_exist | Ok () -> ()) ;; diff --git a/src/dune_engine/scheduler.ml b/src/dune_engine/scheduler.ml index e7ef85267ae..8535aa233bf 100644 --- a/src/dune_engine/scheduler.ml +++ b/src/dune_engine/scheduler.ml @@ -905,17 +905,17 @@ let wait_for_build_process t pid = ;; let got_shutdown reason = - if !Log.verbose - then ( + let msg = match (reason : Shutdown.Reason.t) with - | Timeout -> Log.info [ Pp.text "Timeout." ] - | Requested -> Log.info [ Pp.text "Shutting down." ] - | Signal signal -> - Log.info [ Pp.textf "Got signal %s, exiting." (Signal.name signal) ]) + | Timeout -> "Timeout" + | Requested -> "Shutting down" + | Signal signal -> sprintf "Got signal %s, exiting." (Signal.name signal) + in + Log.verbose_message msg [] ;; let filesystem_watcher_terminated () = - Log.info [ Pp.textf "Filesystem watcher terminated, exiting." ] + Log.info "Filesystem watcher terminated, exiting." [] ;; type saw_shutdown = diff --git a/src/dune_pkg/lock_dir.ml b/src/dune_pkg/lock_dir.ml index b969025f2a0..0137c1ae980 100644 --- a/src/dune_pkg/lock_dir.ml +++ b/src/dune_pkg/lock_dir.ml @@ -1520,11 +1520,12 @@ module Write_disk = struct let version = pkg.info.version |> Package_version.to_string in sprintf "%s.%s" name version) in - [ Pp.textf - "Dependency solution for %s:" - (Path.to_string_maybe_quoted lock_dir_path_external) - ; Pp.enumerate ~f:Pp.text pkgs - ]); + Log.Message.create + `Info + "Dependency solution" + [ "lock_dir", Dyn.string (Path.to_string_maybe_quoted lock_dir_path_external) + ; "packages", Dyn.list Dyn.string pkgs + ]); Path.mkdir_p parent_dir; Temp.with_temp_dir ~parent_dir ~prefix:"dune" ~suffix:"lock" ~f:build | None -> diff --git a/src/dune_pkg/rev_store.ml b/src/dune_pkg/rev_store.ml index 386f6a7971b..4430f9c31ba 100644 --- a/src/dune_pkg/rev_store.ml +++ b/src/dune_pkg/rev_store.ml @@ -150,16 +150,16 @@ module Cache = struct (let path = Path.relative (Lazy.force Dune_util.cache_root_dir) "rev_store" in let rev_store_cache = Dune_config.Config.get rev_store_cache in Log.info - [ Pp.textf - "Revision store cache: %s" - (Dune_config.Config.Toggle.to_string rev_store_cache) - ]; + "Revision store cache" + [ "status", Dune_config.Config.Toggle.to_dyn rev_store_cache ]; match rev_store_cache with + | `Disabled -> None | `Enabled -> Path.mkdir_p path; - Log.info [ Pp.textf "Revision store cache location: %s" (Path.to_string path) ]; - Some path - | `Disabled -> None) + Log.info + "Revision store cache location" + [ "path", Dyn.string (Path.to_string path) ]; + Some path) ;; let db = @@ -1217,7 +1217,7 @@ let content_of_files t files = let git_repo_dir = lazy (let dir = Path.relative (Lazy.force Dune_util.cache_root_dir) "git-repo" in - Log.info [ Pp.textf "Git repository cache location: %s" (Path.to_string dir) ]; + Log.info "Git repository cache location" [ "dir", Path.to_dyn dir ]; dir) ;; diff --git a/src/dune_rpc_server/dune_rpc_server.ml b/src/dune_rpc_server/dune_rpc_server.ml index 8c9df44f7ed..0903f0b9c3b 100644 --- a/src/dune_rpc_server/dune_rpc_server.ml +++ b/src/dune_rpc_server/dune_rpc_server.ml @@ -662,13 +662,12 @@ struct (match exn.exn with | Dune_util.Report_error.Already_reported -> () | _ -> - Log.info - [ Pp.textf - "encountered error serving rpc client (id %d)" - (Session.Id.to_int id) - ; Exn_with_backtrace.pp exn - ]); - Dune_util.Report_error.report exn; + Log.warn + "encountered error serving rpc client" + [ "id", Dyn.int (Session.Id.to_int id) + ; "error", Exn_with_backtrace.to_dyn exn + ]; + Dune_util.Report_error.report exn); session#close) in Event.emit (Session `Stop) id; diff --git a/src/dune_rules/context.ml b/src/dune_rules/context.ml index 4268a68fca8..a175971899c 100644 --- a/src/dune_rules/context.ml +++ b/src/dune_rules/context.ml @@ -696,10 +696,7 @@ module DB = struct native :: targets) in let+ all = List.concat contexts |> Memo.parallel_map ~f:Memo.Lazy.force in - List.iter all ~f:(fun t -> - let open Pp.O in - Log.info - [ Pp.box ~indent:1 (Pp.text "Dune context:" ++ Pp.cut ++ Dyn.pp (to_dyn t)) ]); + List.iter all ~f:(fun t -> Log.info "Dune context" [ "context", to_dyn t ]); all in let memo = Memo.lazy_ ~name:"build-contexts" impl in diff --git a/src/dune_rules/odoc_new.ml b/src/dune_rules/odoc_new.ml index 6a175f98989..c61cafe20ce 100644 --- a/src/dune_rules/odoc_new.ml +++ b/src/dune_rules/odoc_new.ml @@ -182,9 +182,7 @@ module Index = struct of_external_loc maps loc with | Some loc -> loc - | None -> - Log.info [ Pp.textf "Argh lib ex loc: %s" (Lib_name.to_string name) ]; - [ Sub_dir (Lib_name.to_string (Lib.name lib)); Top_dir Other ] + | None -> [ Sub_dir (Lib_name.to_string (Lib.name lib)); Top_dir Other ] ;; let of_pkg maps pkg = @@ -239,7 +237,7 @@ let libs_maps_def = match Path.Map.add acc path i with | Ok acc -> i + 1, acc | Error _ -> - Log.info [ Pp.textf "Error adding findlib path to map" ]; + Log.warn "Error adding findlib path to map" []; i + 1, acc) |> snd in @@ -257,9 +255,10 @@ let libs_maps_def = (match Dune_package.Lib.external_location l with | None -> Log.info - [ Pp.textf - "No location for lib %s" - (Dune_package.Lib.info l |> Lib_info.name |> Lib_name.to_string) + "No location for lib" + [ ( "lib" + , Dyn.string + (Dune_package.Lib.info l |> Lib_info.name |> Lib_name.to_string) ) ]; Memo.return maps | Some location -> @@ -275,11 +274,9 @@ let libs_maps_def = | Ok l -> l | Error _ -> (* I don't expect this should ever happen *) - Log.info - [ Pp.textf - "Error adding lib %s to loc_of_lib map" - (Lib_name.to_string name) - ]; + Log.warn + "Error adding lib to loc_of_lib map" + [ "lib", Dyn.string (Lib_name.to_string name) ]; maps.loc_of_lib in let loc_of_pkg = @@ -298,11 +295,9 @@ let libs_maps_def = (match Lib_name.Map.add libs name (l, lib) with | Ok libs -> Some libs | Error _ -> - Log.info - [ Pp.textf - "Error adding lib %s to libs_of_loc map" - (Lib_name.to_string name) - ]; + Log.warn + "Error adding lib to libs_of_loc map" + [ "lib", Dyn.string (Lib_name.to_string name) ]; Some libs) in let libs_of_loc = @@ -360,11 +355,9 @@ module Classify = struct let classify_location maps location = match Ext_loc_map.find maps.libs_of_loc location with | None -> - Log.info - [ Pp.textf - "classify_local_dir: No lib at this location: %s" - (Dyn.to_string (Dune_package.External_location.to_dyn location)) - ]; + Log.warn + "classify_local_dir: No lib at this location" + [ "location", Dune_package.External_location.to_dyn location ]; Memo.return Nothing | Some libs -> (try @@ -539,11 +532,9 @@ module Valid = struct match Lib_name.Map.add cats.local (Lib.name (llib :> Lib.t)) llib with | Ok l -> l | Error _ -> - Log.info - [ Pp.textf - "Error adding local library %s to categorized map" - (Lib.name (llib :> Lib.t) |> Lib_name.to_string) - ]; + Log.warn + "Error adding local library to categorized map" + [ "lib", Dyn.string (Lib.name (llib :> Lib.t) |> Lib_name.to_string) ]; cats.local in Memo.return { cats with local } @@ -552,7 +543,8 @@ module Valid = struct (match Lib_name.Map.find maps.loc_of_lib (Lib.name lib) with | None -> Log.info - [ Pp.textf "No location for lib: %s" (Lib.name lib |> Lib_name.to_string) ]; + "No location for lib" + [ "lib", Dyn.string (Lib.name lib |> Lib_name.to_string) ]; Memo.return cats | Some location -> let* classification = Classify.classify_location maps location in @@ -565,11 +557,9 @@ module Valid = struct let loc_str = Dyn.to_string (Dune_package.External_location.to_dyn location) in - Log.info - [ Pp.textf - "Duplicate 'Dune_with_modules' library found in location %s" - loc_str - ]; + Log.warn + "Duplicate 'Dune_with_modules' library found in location" + [ "location", Dyn.string loc_str ]; old in let externals = Ext_loc_map.update cats.externals location ~f in @@ -1481,11 +1471,9 @@ let index_info_of_lib_def = | None -> (* Note this shouldn't happen as we've filtered out libs without a [Modules.t] in the classification stage. *) - Log.info - [ Pp.textf - "Expecting modules info for library %s" - (Lib.name lib |> Lib_name.to_string) - ]; + Log.warn + "Expecting modules info for library" + [ "lib", Dyn.string (Lib.name lib |> Lib_name.to_string) ]; [] in let libs = diff --git a/src/dune_rules/pkg_toolchain.ml b/src/dune_rules/pkg_toolchain.ml index 4339b73214f..f2aa2cd974e 100644 --- a/src/dune_rules/pkg_toolchain.ml +++ b/src/dune_rules/pkg_toolchain.ml @@ -3,7 +3,7 @@ open Import let base_dir = lazy (let dir = Path.relative (Lazy.force Dune_util.cache_root_dir) "toolchains" in - Log.info [ Pp.textf "Toolchains cache location: %s" (Path.to_string dir) ]; + Log.info "Toolchains cache location" [ "dir", Dyn.string (Path.to_string dir) ]; Path.as_outside_build_dir_exn dir) ;; diff --git a/src/dune_threaded_console/dune_threaded_console.ml b/src/dune_threaded_console/dune_threaded_console.ml index c98b980e289..51efac4d7d8 100644 --- a/src/dune_threaded_console/dune_threaded_console.ml +++ b/src/dune_threaded_console/dune_threaded_console.ml @@ -73,14 +73,19 @@ let make ~frames_per_second (module Base : S) : (module Dune_console.Backend) = let cleanup exn = state.finished <- true; Option.iter exn ~f:(fun exn -> - Log.info [ Pp.text "Console failed"; Exn_with_backtrace.pp exn ]); + Log.warn "Console failed" [ "error", Exn_with_backtrace.to_dyn exn ]); (match Exn_with_backtrace.try_with Base.finish with | Ok () -> () | Error exn -> (* we can't log to console because we are cleaning it up and we borked it *) Log.log (fun () -> - [ Pp.text "Error cleaning up console"; Exn_with_backtrace.pp exn ])); + Log.Message.create + `Warn + "threaded console error" + [ "error", Exn_with_backtrace.to_dyn exn + ; "message", Dyn.string "Error cleaning up console" + ])); Condition.broadcast finish_cv; Mutex.unlock mutex in diff --git a/src/dune_trace/category.ml b/src/dune_trace/category.ml index de1ac6b5d55..8102b59fc8a 100644 --- a/src/dune_trace/category.ml +++ b/src/dune_trace/category.ml @@ -16,6 +16,7 @@ type t = | Config | File_watcher | Diagnostics + | Log let all = [ Rpc @@ -33,6 +34,7 @@ let all = ; Config ; File_watcher ; Diagnostics + ; Log ] ;; @@ -52,6 +54,7 @@ let to_string = function | Config -> "config" | File_watcher -> "file_watcher" | Diagnostics -> "diagnostics" + | Log -> "log" ;; let of_string = @@ -83,5 +86,6 @@ module Set = Bit_set.Make (struct | Config -> 12 | File_watcher -> 13 | Diagnostics -> 14 + | Log -> 15 ;; end) diff --git a/src/dune_trace/category.mli b/src/dune_trace/category.mli index d39abd31888..1a791a0a8c2 100644 --- a/src/dune_trace/category.mli +++ b/src/dune_trace/category.mli @@ -14,6 +14,7 @@ type t = | Config | File_watcher | Diagnostics + | Log val to_string : t -> string val of_string : string -> t option diff --git a/src/dune_trace/dune_trace.mli b/src/dune_trace/dune_trace.mli index b0e689fcb15..502baca855d 100644 --- a/src/dune_trace/dune_trace.mli +++ b/src/dune_trace/dune_trace.mli @@ -17,6 +17,7 @@ module Category : sig | Config | File_watcher | Diagnostics + | Log val of_string : string -> t option end @@ -87,6 +88,7 @@ module Event : sig val resolve_targets : Path.t list -> alias list -> t val load_dir : Path.t -> t + val log : Log.Message.t -> t val file_watcher : [ `File of Path.t * [ `Created | `Deleted | `File_changed | `Unknown ] diff --git a/src/dune_trace/event.ml b/src/dune_trace/event.ml index 5213daa860b..b41000d2fb7 100644 --- a/src/dune_trace/event.ml +++ b/src/dune_trace/event.ml @@ -413,3 +413,17 @@ let error loc kind exn backtrace memo_stack = in Event.instant ~name ~args now Diagnostics ;; + +let log { Log.Message.level; message; args } = + let now = Time.now () in + let name = + match level with + | `Warn -> "warn" + | `Info -> "info" + | `Verbose -> "verbose" + in + let args = + ("message", `String message) :: List.map args ~f:(fun (name, v) -> name, Arg.dyn v) + in + Event.instant ~args ~name now Log +;; diff --git a/src/dune_util/persistent.ml b/src/dune_util/persistent.ml index e74df27e561..b59dd2846e5 100644 --- a/src/dune_util/persistent.ml +++ b/src/dune_util/persistent.ml @@ -89,15 +89,9 @@ module Make (D : Desc) = struct then ( match (Marshal.from_channel ic : D.t) with | exception Failure f -> - Log.info_user_message - (User_message.make - [ Pp.tag - User_message.Style.Warning - (Pp.textf - "Failed to load corrupted file %s: %s" - (Path.to_string file) - f) - ]); + Log.warn + "Failed to load corrupted file" + [ "file", Dyn.string (Path.to_string file); "error", Dyn.string f ]; None | d -> Some d) else None) diff --git a/test/blackbox-tests/test-cases/cmdline/profile.t b/test/blackbox-tests/test-cases/cmdline/profile.t index c06793db0ee..e38c24c2345 100644 --- a/test/blackbox-tests/test-cases/cmdline/profile.t +++ b/test/blackbox-tests/test-cases/cmdline/profile.t @@ -6,19 +6,45 @@ Bug #4632 > (lang dune 3.13) > EOF - $ dune build --verbose 2>&1 | grep "; profile" - ; profile = Dev - - $ dune build --release --verbose 2>&1 | grep "; profile" - ; profile = Release + $ runtest() { + > dune build --trace-file trace.json $@ + > jq '.[] | select(.cat == "log" and .args.message == "Dune context") | .args.context | .[] | select(.[0] == "profile")' trace.json + > } + + $ runtest + [ + "profile", + "Dev" + ] + + $ runtest --release + [ + "profile", + "Release" + ] $ export DUNE_PROFILE=envvar - $ dune build --verbose 2>&1 | grep "; profile" - ; profile = User_defined "envvar" - - $ dune build --release --verbose 2>&1 | grep "; profile" - ; profile = Release - - $ dune build --profile cmdline --verbose 2>&1 | grep "; profile" - ; profile = User_defined "cmdline" + $ runtest + [ + "profile", + [ + "User_defined", + "envvar" + ] + ] + + $ runtest --release + [ + "profile", + "Release" + ] + + $ runtest --profile cmdline + [ + "profile", + [ + "User_defined", + "cmdline" + ] + ] diff --git a/test/blackbox-tests/test-cases/corrupt-persistent.t b/test/blackbox-tests/test-cases/corrupt-persistent.t index 4c1f397e6b1..509b32862cb 100644 --- a/test/blackbox-tests/test-cases/corrupt-persistent.t +++ b/test/blackbox-tests/test-cases/corrupt-persistent.t @@ -14,6 +14,10 @@ Delete last 10 chars of the .db file to corrupt it Dune log the corrupted file and recover - $ dune build a - $ grep "truncated object" _build/log - # Failed to load corrupted file _build/.db: input_value: truncated object + $ dune build --trace-file trace.json a + $ jq '.[] | select(.cat == "log" and (.args.message | contains("corrupt"))) | .args' trace.json + { + "message": "Warning: Failed to load corrupted file", + "file": "_build/.db", + "error": "input_value: truncated object" + } diff --git a/test/blackbox-tests/test-cases/custom-build-dir.t/run.t b/test/blackbox-tests/test-cases/custom-build-dir.t/run.t index 8d47b08b2cb..5a73ce5a8c7 100644 --- a/test/blackbox-tests/test-cases/custom-build-dir.t/run.t +++ b/test/blackbox-tests/test-cases/custom-build-dir.t/run.t @@ -2,7 +2,6 @@ _foobar _foobar/default _foobar/default/foo - _foobar/log $ rm -rf _foobar @@ -35,7 +34,6 @@ Test with build directory being an absolute path build build/default build/default/foo - build/log $ rm -rf build diff --git a/test/blackbox-tests/test-cases/dune-init/dune-init-proj-no-spurious-build-dir.t b/test/blackbox-tests/test-cases/dune-init/dune-init-proj-no-spurious-build-dir.t index 3451de2b29c..91c6fc17812 100644 --- a/test/blackbox-tests/test-cases/dune-init/dune-init-proj-no-spurious-build-dir.t +++ b/test/blackbox-tests/test-cases/dune-init/dune-init-proj-no-spurious-build-dir.t @@ -11,9 +11,9 @@ directory in the current directory. > } $ ls + _build foo $ ls foo - _build bin dune-project foo.opam @@ -25,10 +25,10 @@ directory in the current directory. Success: initialized project component named foo Leaving directory 'bar' $ ls + _build bar foo $ ls bar - _build bar bin dune-project @@ -42,11 +42,11 @@ directory in the current directory. Success: initialized project component named foo Leaving directory 'baz' $ ls + _build bar baz foo $ ls baz - _build baz bin dune-project diff --git a/test/blackbox-tests/test-cases/dune-init/dune-init.t/run.t b/test/blackbox-tests/test-cases/dune-init/dune-init.t/run.t index 7e26281a076..c34b7fdd325 100644 --- a/test/blackbox-tests/test-cases/dune-init/dune-init.t/run.t +++ b/test/blackbox-tests/test-cases/dune-init/dune-init.t/run.t @@ -319,9 +319,6 @@ The generated project contains all expected subcomponents: new_exec_proj/dune-project new_exec_proj/new_exec_proj.opam - new_exec_proj/_build: - log - new_exec_proj/bin: dune main.ml @@ -441,9 +438,6 @@ The generated project contains all expected subcomponents: new_lib_proj/dune-project new_lib_proj/new_lib_proj.opam - new_lib_proj/_build: - log - new_lib_proj/lib: dune @@ -573,9 +567,6 @@ The `esy` project contains all expected subcomponents: new_esy_proj/dune-project new_esy_proj/package.json - new_esy_proj/_build: - log - new_esy_proj/bin: dune main.ml diff --git a/test/blackbox-tests/test-cases/exec/exec-cmd.t/run.t b/test/blackbox-tests/test-cases/exec/exec-cmd.t/run.t index 342d56473fb..73367789728 100644 --- a/test/blackbox-tests/test-cases/exec/exec-cmd.t/run.t +++ b/test/blackbox-tests/test-cases/exec/exec-cmd.t/run.t @@ -29,3 +29,4 @@ $ ls -a test/_build . .. + trace.json diff --git a/test/blackbox-tests/test-cases/pkg/log-solution.t b/test/blackbox-tests/test-cases/pkg/log-solution.t index 85baf6711ca..7f20557b851 100644 --- a/test/blackbox-tests/test-cases/pkg/log-solution.t +++ b/test/blackbox-tests/test-cases/pkg/log-solution.t @@ -16,30 +16,39 @@ log. Running the solver explicitely should write the solution into the build log: $ mkpkg foo 0.0.1 - $ dune pkg lock + $ dune pkg lock --trace-file trace.json Solution for dune.lock Dependencies common to all supported platforms: - foo.0.0.1 + We should be seeing that it has created a lock dir solution depending on foo.0.0.1: - $ dune_cmd print-from "Dependency solution for" < _build/log - # Dependency solution for dune.lock: - # - foo.0.0.1 + $ jq '.[] | select(.cat == "log" and .args.message == "Dependency solution") | .args' trace.json + { + "message": "Dependency solution", + "lock_dir": "dune.lock", + "packages": [ + "foo.0.0.1" + ] + } It should also work when the lock dir is generated by Dune: $ rm -r "${source_lock_dir}" $ mkpkg foo 0.0.2 - $ dune build + $ dune build --trace-file trace.json We should be seeing that it has created a lock dir solution depending on foo.0.0.2: - $ dune_cmd print-from 'Dependency solution for' < _build/log | grep '^#' | dune_cmd subst '.sandbox/[a-f0-9]*' '.sandbox/$HASH' - # Dependency solution for - # _build/.sandbox/$HASH/_private/default/.lock/dune.lock: - # - foo.0.0.2 + $ jq '.[] | select(.cat == "log" and .args.message == "Dependency solution") | .args | del(.lock_dir)' trace.json + { + "message": "Dependency solution", + "packages": [ + "foo.0.0.2" + ] + } Show the order and formatting of packages @@ -61,18 +70,21 @@ Depend on these new packages in a random order > (allow_empty)) > EOF - $ dune build + $ dune build --trace-file trace.json The order should of dependencies should be non-random: - $ dune_cmd print-from 'Dependency solution for' < _build/log | grep '^#' | dune_cmd subst '\.sandbox/[a-f0-9]*' '.sandbox/$HASH' - # Dependency solution for - # _build/.sandbox/$HASH/_private/default/.lock/dune.lock: - # - aaaaaaa.0.0.1 - # - bbbbbbb.0.0.1 - # - ccccccc.0.0.1 - # - ddddddd.0.0.1 - # - eeeeeee.0.0.1 - # - fffffff.0.0.1 - # - foo.0.0.2 - # - ggggggg.0.0.1 + $ jq '.[] | select(.cat == "log" and .args.message == "Dependency solution") | .args | del(.lock_dir)' trace.json + { + "message": "Dependency solution", + "packages": [ + "aaaaaaa.0.0.1", + "bbbbbbb.0.0.1", + "ccccccc.0.0.1", + "ddddddd.0.0.1", + "eeeeeee.0.0.1", + "fffffff.0.0.1", + "foo.0.0.2", + "ggggggg.0.0.1" + ] + } diff --git a/test/blackbox-tests/test-cases/pkg/portable-lockdirs/portable-lockdirs-partial-solve.t b/test/blackbox-tests/test-cases/pkg/portable-lockdirs/portable-lockdirs-partial-solve.t index 29c1b6f52f6..e697af39fa7 100644 --- a/test/blackbox-tests/test-cases/pkg/portable-lockdirs/portable-lockdirs-partial-solve.t +++ b/test/blackbox-tests/test-cases/pkg/portable-lockdirs/portable-lockdirs-partial-solve.t @@ -31,7 +31,7 @@ Make a package that is only available on macos. Solving will still succeed, but there'll be a warning because dune will attempt to solve for macos, linux, and windows by default. - $ dune pkg lock + $ dune pkg lock --trace-file trace.json Solution for dune.lock Dependencies common to all supported platforms: @@ -43,22 +43,32 @@ to solve for macos, linux, and windows by default. - arch = arm64; os = linux - arch = x86_64; os = linux - See the log or run with --verbose for more details. Configure platforms to + See the trace file with --trace-file for more details. Configure platforms to solve for in the dune-workspace file. The log file will contain errors about the package being unavailable. - $ dune_cmd print-from "The dependency solver failed to find a solution for the following platforms:" < _build/log - # The dependency solver failed to find a solution for the following platforms: - # - arch = x86_64; os = linux - # - arch = arm64; os = linux - # ...with this error: - # Couldn't solve the package dependency formula. - # Selected candidates: x.dev - # - foo -> (problem) - # No usable implementations: - # foo.0.0.1: Availability condition not satisfied - # Dependency solution for dune.lock: - # - foo.0.0.1 + $ jqScript=$(mktemp) + $ cat >$jqScript < .[] | + > select(.cat == "log" and .args.message != "ocamlparam" and (.args.message | contains("Shared cache") | not)) | + > .args + > EOF + $ jq -f $jqScript trace.json + { + "message": "Workspace root", + "root": "$TESTCASE_ROOT" + } + { + "message": "Solver found partial solution", + "error_count": "1" + } + { + "message": "Dependency solution", + "lock_dir": "dune.lock", + "packages": [ + "foo.0.0.1" + ] + } The lockdir will contain a list of the platforms where solving succeeded. $ cat ${default_lock_dir}/lock.dune diff --git a/test/blackbox-tests/test-cases/promote/promote-variables.t b/test/blackbox-tests/test-cases/promote/promote-variables.t index aa7bd21179a..73423ea1237 100644 --- a/test/blackbox-tests/test-cases/promote/promote-variables.t +++ b/test/blackbox-tests/test-cases/promote/promote-variables.t @@ -22,4 +22,3 @@ Test expanding variables in `(promote (into ..))` $ cat another/promoted Hello, world! - diff --git a/test/blackbox-tests/test-cases/trace-file.t/dune b/test/blackbox-tests/test-cases/trace-file.t/dune index cb8db83ab8d..53563f875ea 100644 --- a/test/blackbox-tests/test-cases/trace-file.t/dune +++ b/test/blackbox-tests/test-cases/trace-file.t/dune @@ -1,3 +1,2 @@ (executable - (name prog) -) + (name prog))