From 8ec644340f29325aa79a233c29b349d1ef816ec7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20Bara=C3=BAna?= Date: Fri, 3 Oct 2025 14:36:31 -0300 Subject: [PATCH] Add structured metadata to code evaluation logs This will be easier to process from an external log aggregator. Useful when auditing code evalution in an app server connected to a prod environment. --- README.md | 10 +++++++--- lib/livebook.ex | 2 ++ lib/livebook/session.ex | 25 +++++++++++++++++++++---- lib/livebook/utils.ex | 5 ++++- 4 files changed, 34 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index b684a991f..5259d1523 100644 --- a/README.md +++ b/README.md @@ -265,9 +265,13 @@ The following environment variables can be used to configure Livebook on boot: logging, either of: error, warning, notice, info, debug. Defaults to warning. * `LIVEBOOK_LOG_METADATA` - a comma-separated list of metadata keys that should - be included in the log messages. Currently the only Livebook-spcecific key is - users (attached to evaluation and request logs). By default includes only - request_id. + be included in the log messages. Livebook-specific keys include: + - `users` (attached to evaluation and request logs) + - `session_mode` (attached to evaluation logs, either "default" or "app") + - `code` (attached to evaluation logs, the code being evaluated) + - `event` (attached to evaluation logs, currently always "code.evaluate") + + By default includes only `request_id`. * `LIVEBOOK_LOG_FORMAT` - sets the log output format, either "text" (default) for human-readable logs or "json" for structured JSON. diff --git a/lib/livebook.ex b/lib/livebook.ex index f5269797d..bcf9a6b08 100644 --- a/lib/livebook.ex +++ b/lib/livebook.ex @@ -104,6 +104,8 @@ defmodule Livebook do log_metadata = Livebook.Config.log_metadata!("LIVEBOOK_LOG_METADATA") log_format = Livebook.Config.log_format!("LIVEBOOK_LOG_FORMAT") || :text + config :livebook, :log_format, log_format + case {log_format, log_metadata} do {:json, log_metadata} -> config :logger, :default_handler, diff --git a/lib/livebook/session.ex b/lib/livebook/session.ex index d7c28b12c..261bc8801 100644 --- a/lib/livebook/session.ex +++ b/lib/livebook/session.ex @@ -2685,8 +2685,20 @@ defmodule Livebook.Session do end def log_code_evaluation(cell, state) do + inspected_code = inspect(cell.source, printable_limit: :infinity) + + # For metadata code, we try to use use the raw source, so it's easier to process + # the logged code in a external log aggregator. + metadata_code = + case cell.source do + source when is_binary(source) -> source + _ -> inspected_code + end + + session_mode = state.data.mode + evaluation_users = - case state.data.mode do + case session_mode do :default -> Map.values(state.data.users_map) :app -> if(state.deployed_by, do: [state.deployed_by], else: []) end @@ -2695,12 +2707,17 @@ defmodule Livebook.Session do [ """ Evaluating code - Session mode: #{state.data.mode} + Session mode: #{session_mode} Code: \ """, - inspect(cell.source, printable_limit: :infinity) + inspected_code ], - Livebook.Utils.logger_users_metadata(evaluation_users) + Keyword.merge( + Livebook.Utils.logger_users_metadata(evaluation_users), + session_mode: session_mode, + code: metadata_code, + event: "code.evaluate" + ) ) end diff --git a/lib/livebook/utils.ex b/lib/livebook/utils.ex index 73a0c8a7c..f781199ff 100644 --- a/lib/livebook/utils.ex +++ b/lib/livebook/utils.ex @@ -854,6 +854,9 @@ defmodule Livebook.Utils do into: %{} end - [users: inspect(list)] + case Application.get_env(:livebook, :log_format) do + :text -> [users: inspect(list)] + :json -> [users: list] + end end end