 bondscell_results $e1be3bfb-0764-435d-872f-e073ca3c3ee8queued¤logslinemsgThis is an error messagetext/plaincell_id$e1be3bfb-0764-435d-872f-e073ca3c3ee8kwargsidMain_workspace#2_52445b6efilep/home/runner/work/JuliaWorkshopAISF/JuliaWorkshopAISF/Lesson2/logging.jl#==#e1be3bfb-0764-435d-872f-e073ca3c3ee8grouplogginglevelErrorlinemsgThis is a warn messagetext/plaincell_id$e1be3bfb-0764-435d-872f-e073ca3c3ee8kwargsidMain_workspace#2_b16ebfe9filep/home/runner/work/JuliaWorkshopAISF/JuliaWorkshopAISF/Lesson2/logging.jl#==#e1be3bfb-0764-435d-872f-e073ca3c3ee8grouplogginglevelWarnlinemsgThis is an info messagetext/plaincell_id$e1be3bfb-0764-435d-872f-e073ca3c3ee8kwargsidMain_workspace#2_6f42f2f9filep/home/runner/work/JuliaWorkshopAISF/JuliaWorkshopAISF/Lesson2/logging.jl#==#e1be3bfb-0764-435d-872f-e073ca3c3ee8grouplogginglevelInfolinemsgThis is a debug messagetext/plaincell_id$e1be3bfb-0764-435d-872f-e073ca3c3ee8kwargsidMain_workspace#2_2151730cfilep/home/runner/work/JuliaWorkshopAISF/JuliaWorkshopAISF/Lesson2/logging.jl#==#e1be3bfb-0764-435d-872f-e073ca3c3ee8grouplogginglevelDebugrunning¦outputbodymimetext/plainrootassigneelast_run_timestampAj)|persist_js_state·has_pluto_hook_features§cell_id$e1be3bfb-0764-435d-872f-e073ca3c3ee8depends_on_disabled_cells§runtime !published_object_keysdepends_on_skipped_cells§errored$9117b3c6-80af-463d-8e4d-a35bef1023acqueued¤logsrunning¦outputbodyٸ<div class="markdown"><h2>TransformerLogger</h2>
<p>This allows to transform the log received, not just the log message. A nice example is to add the time to the log message</p>
</div>mimetext/htmlrootassigneelast_run_timestampAj'UWpersist_js_state·has_pluto_hook_features§cell_id$9117b3c6-80af-463d-8e4d-a35bef1023acdepends_on_disabled_cells§runtime 7|published_object_keysdepends_on_skipped_cells§errored$57e26ae6-3972-4d86-8f66-0932192139fcqueued¤logsrunning¦outputbody<div class="markdown"><h2>TeeLogger</h2>
<p>There are many Loggers defined in <code>LoggingExtras</code> and we probably won&#39;t have time to go through all of them. Let&#39;s start with the <code>TeeLogger</code> or <code>demux</code>, this simply reroutes the log messages to different loggers. The interface of the constructor is:</p>
<pre><code class="language-julia">TeeLogger&#40;loggers::AbstractLogger...&#41;</code></pre>
<p>and the log message will be passed to all the loggers passed. A possible usage of it could be to print the debug messages in a different place respect to the info messages, in this way we would have a more clean space where we have only the imporant messages, and another place where we have detailed informations about the running code.</p>
</div>mimetext/htmlrootassigneelast_run_timestampAj'Q4persist_js_state·has_pluto_hook_features§cell_id$57e26ae6-3972-4d86-8f66-0932192139fcdepends_on_disabled_cells§runtime Fpublished_object_keysdepends_on_skipped_cells§errored$0dc51c5f-9a79-406a-ad52-5929283e9013queued¤logslinemsg$I'm an unicorn with a rainbow mantletext/plaincell_id$0dc51c5f-9a79-406a-ad52-5929283e9013kwargsidMain_workspace#2_b73cf65dfilep/home/runner/work/JuliaWorkshopAISF/JuliaWorkshopAISF/Lesson2/logging.jl#==#0dc51c5f-9a79-406a-ad52-5929283e9013grouplogginglevelInforunning¦outputbodymimetext/plainrootassigneelast_run_timestampAj)persist_js_state·has_pluto_hook_features§cell_id$0dc51c5f-9a79-406a-ad52-5929283e9013depends_on_disabled_cells§runtime@2Hpublished_object_keysdepends_on_skipped_cells§errored$c1a949d5-adb4-444c-be32-b8904a49d198queued¤logsrunning¦outputbody<div class="markdown"><h2>FileLogger</h2>
<p>This logs to a file, let&#39;s see a more complex exampl combining the previous types</p>
<pre><code class="language-julia-repl">julia&gt; using LoggingExtras;

julia&gt; demux_logger &#61; TeeLogger&#40;
    MinLevelLogger&#40;FileLogger&#40;&quot;info.log&quot;&#41;, Logging.Info&#41;,
    MinLevelLogger&#40;FileLogger&#40;&quot;warn.log&quot;&#41;, Logging.Warn&#41;,
&#41;;


julia&gt; with_logger&#40;demux_logger&#41; do
    	@warn&#40;&quot;It is bad&quot;&#41;
    	@info&#40;&quot;normal stuff&quot;&#41;
    	@error&#40;&quot;THE WORSE THING&quot;&#41;
    	@debug&#40;&quot;it is chill&quot;&#41;
	end

shell&gt;  cat warn.log
┌ Warning: It is bad
└ @ Main REPL&#91;34&#93;:2
┌ Error: THE WORSE THING
└ @ Main REPL&#91;34&#93;:4

shell&gt;  cat info.log
┌ Warning: It is bad
└ @ Main REPL&#91;34&#93;:2
┌ Info: normal stuff
└ @ Main REPL&#91;34&#93;:3
┌ Error: THE WORSE THING
└ @ Main REPL&#91;34&#93;:4</code></pre>
</div>mimetext/htmlrootassigneelast_run_timestampAj'URpersist_js_state·has_pluto_hook_features§cell_id$c1a949d5-adb4-444c-be32-b8904a49d198depends_on_disabled_cells§runtime ̇published_object_keysdepends_on_skipped_cells§errored$cd7d1a77-533c-4898-863b-6f4030666886queued¤logsrunning¦outputbodymimetext/plainrootassigneelast_run_timestampAj)HMbpersist_js_state·has_pluto_hook_features§cell_id$cd7d1a77-533c-4898-863b-6f4030666886depends_on_disabled_cells§runtimepublished_object_keysdepends_on_skipped_cells§errored$81f9d9a8-c138-417d-b90b-89b56d54be16queued¤logslinemsgYou will only see thistext/plaincell_id$81f9d9a8-c138-417d-b90b-89b56d54be16kwargsidMain_workspace#2_e26b1b23filep/home/runner/work/JuliaWorkshopAISF/JuliaWorkshopAISF/Lesson2/logging.jl#==#81f9d9a8-c138-417d-b90b-89b56d54be16grouplogginglevelErrorrunning¦outputbodymimetext/plainrootassigneelast_run_timestampAj)?persist_js_state·has_pluto_hook_features§cell_id$81f9d9a8-c138-417d-b90b-89b56d54be16depends_on_disabled_cells§runtime
published_object_keysdepends_on_skipped_cells§errored$d80331e9-f2c9-4689-9c87-125d7082e7a9queued¤logslinemsg2This is an error with an exception and a backtracetext/plaincell_id$d80331e9-f2c9-4689-9c87-125d7082e7a9kwargsexceptionmsgArgumentError: somethingstacktracecall_shortmacro expansioninlinedãurlpath>./logging/logging.jl#@#==#d80331e9-f2c9-4689-9c87-125d7082e7a9source_packagecallmacro expansionlinfo_typeNothinglinefile4logging.jl#@#==#d80331e9-f2c9-4689-9c87-125d7082e7a9funcmacro expansionparent_modulefrom_ccall_short(::var"#foo1#1")()inlined£urlٛhttps://github.com/AISF-Pisa/JuliaWorkshopAISF/tree/8edb0b116314aa7fc6a117bb99e07aee715e0335//Lesson2/logging.jl#==#d80331e9-f2c9-4689-9c87-125d7082e7a9#L2pathp/home/runner/work/JuliaWorkshopAISF/JuliaWorkshopAISF/Lesson2/logging.jl#==#d80331e9-f2c9-4689-9c87-125d7082e7a9source_packageMaincall(::var"#foo1#1")()linfo_typeCore.MethodInstancelinefile2logging.jl#==#d80331e9-f2c9-4689-9c87-125d7082e7a9funcfoo1parent_moduleMain.var"workspace#4"from_ccall_shorttop-level scopeinlined£urlpathp/home/runner/work/JuliaWorkshopAISF/JuliaWorkshopAISF/Lesson2/logging.jl#==#d80331e9-f2c9-4689-9c87-125d7082e7a9source_packagecalltop-level scopelinfo_typeCore.CodeInfolinefile2logging.jl#==#d80331e9-f2c9-4689-9c87-125d7082e7a9functop-level scopeparent_modulefrom_c'application/vnd.pluto.stacktrace+objectidMain_workspace#2_5aac318bfilep/home/runner/work/JuliaWorkshopAISF/JuliaWorkshopAISF/Lesson2/logging.jl#==#d80331e9-f2c9-4689-9c87-125d7082e7a9grouplogginglevelErrorlinemsg4This will be shown since we haven't trhown the errortext/plaincell_id$d80331e9-f2c9-4689-9c87-125d7082e7a9kwargsidMain_workspace#2_619151e9filep/home/runner/work/JuliaWorkshopAISF/JuliaWorkshopAISF/Lesson2/logging.jl#==#d80331e9-f2c9-4689-9c87-125d7082e7a9grouplogginglevelInforunning¦outputbodymimetext/plainrootassigneelast_run_timestampAj)rpersist_js_state·has_pluto_hook_features§cell_id$d80331e9-f2c9-4689-9c87-125d7082e7a9depends_on_disabled_cells§runtime	+published_object_keysdepends_on_skipped_cells§errored$e7a7867d-56e3-4524-b3c2-5fcf6dc7c6f8queued¤logsrunning¦outputbody<div class="markdown"><div class="admonition note"><p class="admonition-title">Note</p><p>Pluto doesn&#39;t allow to set the global logger since each cell is evaluated with a different logger, but the function <code>global_logger&#40;&#91;logger&#93;&#41;</code> returns the current global logger, and if a logger is passed as argument, the global logger is changed.</p>
</div>
</div>mimetext/htmlrootassigneelast_run_timestampAj'TTapersist_js_state·has_pluto_hook_features§cell_id$e7a7867d-56e3-4524-b3c2-5fcf6dc7c6f8depends_on_disabled_cells§runtime published_object_keysdepends_on_skipped_cells§errored$ca6dd602-d5d6-496d-9711-783925d39764queued¤logslinemsgThis is an info messagetext/plaincell_id$ca6dd602-d5d6-496d-9711-783925d39764kwargsAprefixInt64elements1text/plain2text/plain3text/plaintypeArrayprefix_shortobjectida2b429ac028676d3!application/vnd.pluto.tree+objectidMain_workspace#2_fd93d088filep/home/runner/work/JuliaWorkshopAISF/JuliaWorkshopAISF/Lesson2/logging.jl#==#ca6dd602-d5d6-496d-9711-783925d39764grouplogginglevelInfolinemsgyou can also use keywordtext/plaincell_id$ca6dd602-d5d6-496d-9711-783925d39764kwargsvarprefixInt64elements1text/plain2text/plain3text/plaintypeArrayprefix_shortobjectida2b429ac028676d3!application/vnd.pluto.tree+objectidMain_workspace#2_390dfc7efilep/home/runner/work/JuliaWorkshopAISF/JuliaWorkshopAISF/Lesson2/logging.jl#==#ca6dd602-d5d6-496d-9711-783925d39764grouplogginglevelInforunning¦outputbodymimetext/plainrootassigneelast_run_timestampAj)gpersist_js_state·has_pluto_hook_features§cell_id$ca6dd602-d5d6-496d-9711-783925d39764depends_on_disabled_cells§runtimeYp8published_object_keysdepends_on_skipped_cells§errored$9d3649bc-7a6f-4106-94ff-b10fe0f6ecd7queued¤logslinemsg2This is an error with an exception and a backtracetext/plaincell_id$9d3649bc-7a6f-4106-94ff-b10fe0f6ecd7kwargsexceptionmsgArgumentError: somethingstacktracecall_shortmacro expansioninlinedãurlpath>./logging/logging.jl#@#==#9d3649bc-7a6f-4106-94ff-b10fe0f6ecd7source_packagecallmacro expansionlinfo_typeNothinglinefile4logging.jl#@#==#9d3649bc-7a6f-4106-94ff-b10fe0f6ecd7funcmacro expansionparent_modulefrom_ccall_short(::var"#foo2#2")()inlined£urlٛhttps://github.com/AISF-Pisa/JuliaWorkshopAISF/tree/8edb0b116314aa7fc6a117bb99e07aee715e0335//Lesson2/logging.jl#==#9d3649bc-7a6f-4106-94ff-b10fe0f6ecd7#L2pathp/home/runner/work/JuliaWorkshopAISF/JuliaWorkshopAISF/Lesson2/logging.jl#==#9d3649bc-7a6f-4106-94ff-b10fe0f6ecd7source_packageMaincall(::var"#foo2#2")()linfo_typeCore.MethodInstancelinefile2logging.jl#==#9d3649bc-7a6f-4106-94ff-b10fe0f6ecd7funcfoo2parent_moduleMain.var"workspace#4"from_ccall_shorttop-level scopeinlined£urlpathp/home/runner/work/JuliaWorkshopAISF/JuliaWorkshopAISF/Lesson2/logging.jl#==#9d3649bc-7a6f-4106-94ff-b10fe0f6ecd7source_packagecalltop-level scopelinfo_typeCore.CodeInfolinefile2logging.jl#==#9d3649bc-7a6f-4106-94ff-b10fe0f6ecd7functop-level scopeparent_modulefrom_c'application/vnd.pluto.stacktrace+objectidMain_workspace#2_75c47cc2filep/home/runner/work/JuliaWorkshopAISF/JuliaWorkshopAISF/Lesson2/logging.jl#==#9d3649bc-7a6f-4106-94ff-b10fe0f6ecd7grouplogginglevelErrorrunning¦outputbodymsgArgumentError: somethingstacktracecall_short(::var"#foo2#2")()inlined£urlٛhttps://github.com/AISF-Pisa/JuliaWorkshopAISF/tree/8edb0b116314aa7fc6a117bb99e07aee715e0335//Lesson2/logging.jl#==#9d3649bc-7a6f-4106-94ff-b10fe0f6ecd7#L2pathp/home/runner/work/JuliaWorkshopAISF/JuliaWorkshopAISF/Lesson2/logging.jl#==#9d3649bc-7a6f-4106-94ff-b10fe0f6ecd7source_packageMaincall(::var"#foo2#2")()linfo_typeCore.MethodInstancelinefile2logging.jl#==#9d3649bc-7a6f-4106-94ff-b10fe0f6ecd7funcfoo2parent_moduleMain.var"workspace#4"from_ccall_shorttop-level scopeinlined£urlpathp/home/runner/work/JuliaWorkshopAISF/JuliaWorkshopAISF/Lesson2/logging.jl#==#9d3649bc-7a6f-4106-94ff-b10fe0f6ecd7source_packagecalltop-level scopelinfo_typeCore.CodeInfolinefile2logging.jl#==#9d3649bc-7a6f-4106-94ff-b10fe0f6ecd7functop-level scopeparent_modulefrom_c¤mime'application/vnd.pluto.stacktrace+objectrootassigneelast_run_timestampAj)w:persist_js_state·has_pluto_hook_features§cell_id$9d3649bc-7a6f-4106-94ff-b10fe0f6ecd7depends_on_disabled_cells§runtimepublished_object_keysdepends_on_skipped_cells§errored$537840b2-81d4-4c2a-ab2d-9b6825432f98queued¤logsrunning¦outputbodyٻ<div class="markdown"><h2>MinLevelLogger</h2>
<p>This is a special case of the early filtered logger that checks if the message level is above the level specified when created.</p>
</div>mimetext/htmlrootassigneelast_run_timestampAj'Utpersist_js_state·has_pluto_hook_features§cell_id$537840b2-81d4-4c2a-ab2d-9b6825432f98depends_on_disabled_cells§runtime published_object_keysdepends_on_skipped_cells§errored$4b3aa5b4-0b71-46b4-aaa4-c038e7abb998queued¤logsrunning¦outputbodyّ<div class="markdown"><h2>ActiveFilteredLogger</h2>
<p>This allows to only select some log messages to show based on a filter function</p>
</div>mimetext/htmlrootassigneelast_run_timestampAj'QYpersist_js_state·has_pluto_hook_features§cell_id$4b3aa5b4-0b71-46b4-aaa4-c038e7abb998depends_on_disabled_cells§runtime 9>published_object_keysdepends_on_skipped_cells§errored$091b39ce-ca5f-41df-8bd7-a672db2363a7queued¤logsrunning¦outputbody<div class="markdown"><h3>EarlyFilteredLogger</h3>
<p>This is similar to the <code>ActiveFilteredLogger</code> but the filter function is called before the log message is generated so the filter cannot be based on it, but it can still access:</p>
<ul>
<li><p><code>level</code> the level of the log</p>
</li>
<li><p><code>module</code> which module called the logger</p>
</li>
<li><p><code>id</code> this is a unique identifier of the message</p>
</li>
</ul>
</div>mimetext/htmlrootassigneelast_run_timestampAj'Ut~persist_js_state·has_pluto_hook_features§cell_id$091b39ce-ca5f-41df-8bd7-a672db2363a7depends_on_disabled_cells§runtime εpublished_object_keysdepends_on_skipped_cells§errored$40fea74a-0f17-11f0-2c2c-d356a1a2b91dqueued¤logsrunning¦outputbody<div class="markdown"><h1>Logging</h1>
<p>Logging is very important when writing code, logged messages are used to track the execution of the program, also allowing to more simply identify bugs and debug them.</p>
<p>Julia has two main libraries for logging, the base one <code>Logging</code> and an extended version <code>LoggingExtras</code>.</p>
<p>The main types of logging are:</p>
<ul>
<li><p>Error</p>
</li>
<li><p>Warn</p>
</li>
<li><p>Info</p>
</li>
<li><p>Debug</p>
</li>
</ul>
<p>We can decide which is the minimul level to log, the important thing is that the code below that thersold will not get executed, this allows to mark as debug some expensive checks that we want to perform only when we are performing a debug.</p>
</div>mimetext/htmlrootassigneelast_run_timestampAj'MGpersist_js_state·has_pluto_hook_features§cell_id$40fea74a-0f17-11f0-2c2c-d356a1a2b91ddepends_on_disabled_cells§runtime 
\published_object_keysdepends_on_skipped_cells§errored$67abc344-0920-44cc-87e0-a582c8976ff9queued¤logsline
msg<[2025-05-12 07:52:05] The time will be added to this messagetext/plaincell_id$67abc344-0920-44cc-87e0-a582c8976ff9kwargsidMain_workspace#2_ff2fdc62filep/home/runner/work/JuliaWorkshopAISF/JuliaWorkshopAISF/Lesson2/logging.jl#==#67abc344-0920-44cc-87e0-a582c8976ff9grouplogginglevelInforunning¦outputbodymimetext/plainrootassigneelast_run_timestampAj)q"persist_js_state·has_pluto_hook_features§cell_id$67abc344-0920-44cc-87e0-a582c8976ff9depends_on_disabled_cells§runtimecUpublished_object_keysdepends_on_skipped_cells§errored$4e0636a1-ac8f-4394-8afe-ecf00a2835daqueued¤logsrunning¦outputbody<div class="markdown"><p>We can also add an exception and a backtrace to the <code>@error</code> macro, it is important to know that the exception would not be thrown automatically. This allows to know if an error occurred by reading the log even if the error was catched.</p>
</div>mimetext/htmlrootassigneelast_run_timestampAj'Opersist_js_state·has_pluto_hook_features§cell_id$4e0636a1-ac8f-4394-8afe-ecf00a2835dadepends_on_disabled_cells§runtime 8published_object_keysdepends_on_skipped_cells§errored$8df6d668-11a0-4ed3-82e6-eeaa833bdf1equeued¤logsrunning¦outputbody<div class="markdown"><h2>Log a message</h2>
<p>To log a message, we just need to use the macros <code>@error</code>, <code>@warn</code>, <code>@info</code> and <code>@debug</code>, followed by the message we wish to show</p>
</div>mimetext/htmlrootassigneelast_run_timestampAj'Opersist_js_state·has_pluto_hook_features§cell_id$8df6d668-11a0-4ed3-82e6-eeaa833bdf1edepends_on_disabled_cells§runtime Mpublished_object_keysdepends_on_skipped_cells§errored$b5e0e0cb-3adb-4f2f-a231-170ddc1ee6aaqueued¤logsrunning¦outputbody<div class="markdown"><p>This is the usual setup I use in my own code:</p>
<pre><code class="language-julia">using LoggingExtras, Dates

const date_format &#61; &quot;yyyy-mm-dd HH:MM:SS&quot;

timestamp_logger&#40;logger&#41; &#61;
    TransformerLogger&#40;logger&#41; do log
        merge&#40;log, &#40;; message&#61;&quot;&#91;&#36;&#40;Dates.format&#40;now&#40;&#41;, date_format&#41;&#41;&#93; &#36;&#40;log.message&#41;&quot;&#41;&#41;
    end

demux_logger&#40;infoFileName::AbstractString, debugFileName::AbstractString&#41; &#61; TeeLogger&#40;
    MinLevelLogger&#40;FileLogger&#40;&quot;&#36;infoFileName.info.log&quot;; append&#61;true&#41;, Logging.Info&#41;,
    MinLevelLogger&#40;FileLogger&#40;&quot;&#36;debugFileName.debug.log&quot;; append&#61;true&#41;, Logging.Debug&#41;,
&#41;;
demux_logger&#40;str::AbstractString&#41; &#61; demux_logger&#40;str, str&#41;

demux_logger&#40;joinpath&#40;folder_name, baseFilename&#41;&#41; |&gt; timestamp_logger |&gt; global_logger</code></pre>
</div>mimetext/htmlrootassigneelast_run_timestampAj'Upersist_js_state·has_pluto_hook_features§cell_id$b5e0e0cb-3adb-4f2f-a231-170ddc1ee6aadepends_on_disabled_cells§runtime  published_object_keysdepends_on_skipped_cells§errored$950186f6-1cb1-480d-9898-1033a7fa86d2queued¤logsrunning¦outputbodyٔ<div class="markdown"><p>we can also add variables to it that will be shown togheter with the message, this is very useful when debugging</p>
</div>mimetext/htmlrootassigneelast_run_timestampAj'Opersist_js_state·has_pluto_hook_features§cell_id$950186f6-1cb1-480d-9898-1033a7fa86d2depends_on_disabled_cells§runtime &published_object_keysdepends_on_skipped_cells§errored±cell_dependencies $e1be3bfb-0764-435d-872f-e073ca3c3ee8precedence_heuristic	cell_id$e1be3bfb-0764-435d-872f-e073ca3c3ee8downstream_cells_mapupstream_cells_mapBase.CoreLogging.invokelatestBase.CoreLogging.===@debug#___this_pluto_module_name'Base.CoreLogging.Base.fixup_stdlib_pathBase.CoreLogging.!@warnBase@errorBase.CoreLogging.isa@infoBase.CoreLogging.>=$9117b3c6-80af-463d-8e4d-a35bef1023acprecedence_heuristic	cell_id$9117b3c6-80af-463d-8e4d-a35bef1023acdownstream_cells_mapupstream_cells_map@md_strgetindex$57e26ae6-3972-4d86-8f66-0932192139fcprecedence_heuristic	cell_id$57e26ae6-3972-4d86-8f66-0932192139fcdownstream_cells_mapupstream_cells_map@md_strgetindex$0dc51c5f-9a79-406a-ad52-5929283e9013precedence_heuristic	cell_id$0dc51c5f-9a79-406a-ad52-5929283e9013downstream_cells_maploggerupstream_cells_mapBase.CoreLogging.invokelatestBase.CoreLogging.===with_logger#___this_pluto_module_namestartswithcurrent_logger'Base.CoreLogging.Base.fixup_stdlib_pathBase.CoreLogging.!BaseBase.CoreLogging.isa@infoActiveFilteredLoggerBase.CoreLogging.>=$c1a949d5-adb4-444c-be32-b8904a49d198precedence_heuristic	cell_id$c1a949d5-adb4-444c-be32-b8904a49d198downstream_cells_mapupstream_cells_map@md_strgetindex$cd7d1a77-533c-4898-863b-6f4030666886precedence_heuristiccell_id$cd7d1a77-533c-4898-863b-6f4030666886downstream_cells_mapLoggingExtrasupstream_cells_map$81f9d9a8-c138-417d-b90b-89b56d54be16precedence_heuristic	cell_id$81f9d9a8-c138-417d-b90b-89b56d54be16downstream_cells_maperror_only_loggerupstream_cells_mapwith_loggerBase.CoreLogging.===Base.CoreLogging.invokelatest#___this_pluto_module_namecurrent_logger'Base.CoreLogging.Base.fixup_stdlib_pathBase.CoreLogging.!@warnMinLevelLoggerBase@errorBase.CoreLogging.isa@infoLoggingBase.CoreLogging.>=$d80331e9-f2c9-4689-9c87-125d7082e7a9precedence_heuristic	cell_id$d80331e9-f2c9-4689-9c87-125d7082e7a9downstream_cells_mapupstream_cells_mapBase.CoreLogging.invokelatestBase.CoreLogging.===backtrace#___this_pluto_module_nameArgumentError'Base.CoreLogging.Base.fixup_stdlib_pathBase.CoreLogging.!Base@errorBase.CoreLogging.isa@infoBase.invokelatestBase.CoreLogging.>=$e7a7867d-56e3-4524-b3c2-5fcf6dc7c6f8precedence_heuristic	cell_id$e7a7867d-56e3-4524-b3c2-5fcf6dc7c6f8downstream_cells_mapupstream_cells_map@md_strgetindex$ca6dd602-d5d6-496d-9711-783925d39764precedence_heuristic	cell_id$ca6dd602-d5d6-496d-9711-783925d39764downstream_cells_mapupstream_cells_mapCoreBase.CoreLogging.invokelatestBase.CoreLogging.===Core.UndefVarError#___this_pluto_module_name'Base.CoreLogging.Base.fixup_stdlib_pathBase.CoreLogging.!BaseBase.CoreLogging.isa@infoBase.invokelatestBase.CoreLogging.>=$9d3649bc-7a6f-4106-94ff-b10fe0f6ecd7precedence_heuristic	cell_id$9d3649bc-7a6f-4106-94ff-b10fe0f6ecd7downstream_cells_mapupstream_cells_mapBase.CoreLogging.invokelatestBase.CoreLogging.===backtrace#___this_pluto_module_nameArgumentError'Base.CoreLogging.Base.fixup_stdlib_pathBase.CoreLogging.!Base@errorBase.CoreLogging.isathrow@infoBase.invokelatestBase.CoreLogging.>=$537840b2-81d4-4c2a-ab2d-9b6825432f98precedence_heuristic	cell_id$537840b2-81d4-4c2a-ab2d-9b6825432f98downstream_cells_mapupstream_cells_map@md_strgetindex$4b3aa5b4-0b71-46b4-aaa4-c038e7abb998precedence_heuristic	cell_id$4b3aa5b4-0b71-46b4-aaa4-c038e7abb998downstream_cells_mapupstream_cells_map@md_strgetindex$091b39ce-ca5f-41df-8bd7-a672db2363a7precedence_heuristic	cell_id$091b39ce-ca5f-41df-8bd7-a672db2363a7downstream_cells_mapupstream_cells_map@md_strgetindex$40fea74a-0f17-11f0-2c2c-d356a1a2b91dprecedence_heuristic	cell_id$40fea74a-0f17-11f0-2c2c-d356a1a2b91ddownstream_cells_mapupstream_cells_map@md_strgetindex$67abc344-0920-44cc-87e0-a582c8976ff9precedence_heuristiccell_id$67abc344-0920-44cc-87e0-a582c8976ff9downstream_cells_mapDates$67abc344-0920-44cc-87e0-a582c8976ff9timestamp_loggerdate_formatupstream_cells_map mergewith_loggerBase.CoreLogging.===Base.CoreLogging.invokelatestnow|>#___this_pluto_module_nameTransformerLoggercurrent_logger'Base.CoreLogging.Base.fixup_stdlib_pathBase.CoreLogging.!Dates$67abc344-0920-44cc-87e0-a582c8976ff9Dates.formatBaseBase.CoreLogging.isa@infoBase.CoreLogging.>=$4e0636a1-ac8f-4394-8afe-ecf00a2835daprecedence_heuristic	cell_id$4e0636a1-ac8f-4394-8afe-ecf00a2835dadownstream_cells_mapupstream_cells_map@md_strgetindex$8df6d668-11a0-4ed3-82e6-eeaa833bdf1eprecedence_heuristic	cell_id$8df6d668-11a0-4ed3-82e6-eeaa833bdf1edownstream_cells_mapupstream_cells_map@md_strgetindex$b5e0e0cb-3adb-4f2f-a231-170ddc1ee6aaprecedence_heuristic	cell_id$b5e0e0cb-3adb-4f2f-a231-170ddc1ee6aadownstream_cells_mapupstream_cells_map@md_strgetindex$950186f6-1cb1-480d-9898-1033a7fa86d2precedence_heuristic	cell_id$950186f6-1cb1-480d-9898-1033a7fa86d2downstream_cells_mapupstream_cells_map@md_strgetindexcell_execution_order $cd7d1a77-533c-4898-863b-6f4030666886$67abc344-0920-44cc-87e0-a582c8976ff9$40fea74a-0f17-11f0-2c2c-d356a1a2b91d$8df6d668-11a0-4ed3-82e6-eeaa833bdf1e$e1be3bfb-0764-435d-872f-e073ca3c3ee8$950186f6-1cb1-480d-9898-1033a7fa86d2$ca6dd602-d5d6-496d-9711-783925d39764$4e0636a1-ac8f-4394-8afe-ecf00a2835da$d80331e9-f2c9-4689-9c87-125d7082e7a9$9d3649bc-7a6f-4106-94ff-b10fe0f6ecd7$57e26ae6-3972-4d86-8f66-0932192139fc$4b3aa5b4-0b71-46b4-aaa4-c038e7abb998$0dc51c5f-9a79-406a-ad52-5929283e9013$e7a7867d-56e3-4524-b3c2-5fcf6dc7c6f8$091b39ce-ca5f-41df-8bd7-a672db2363a7$537840b2-81d4-4c2a-ab2d-9b6825432f98$81f9d9a8-c138-417d-b90b-89b56d54be16$9117b3c6-80af-463d-8e4d-a35bef1023ac$c1a949d5-adb4-444c-be32-b8904a49d198$b5e0e0cb-3adb-4f2f-a231-170ddc1ee6aalast_hot_reload_time        shortpathlogging.jlprocess_statusreadypathH/home/runner/work/JuliaWorkshopAISF/JuliaWorkshopAISF/Lesson2/logging.jlpluto_versionv0.20.8last_save_timeAj'FWcell_order $40fea74a-0f17-11f0-2c2c-d356a1a2b91d$8df6d668-11a0-4ed3-82e6-eeaa833bdf1e$e1be3bfb-0764-435d-872f-e073ca3c3ee8$950186f6-1cb1-480d-9898-1033a7fa86d2$ca6dd602-d5d6-496d-9711-783925d39764$4e0636a1-ac8f-4394-8afe-ecf00a2835da$d80331e9-f2c9-4689-9c87-125d7082e7a9$9d3649bc-7a6f-4106-94ff-b10fe0f6ecd7$cd7d1a77-533c-4898-863b-6f4030666886$57e26ae6-3972-4d86-8f66-0932192139fc$4b3aa5b4-0b71-46b4-aaa4-c038e7abb998$0dc51c5f-9a79-406a-ad52-5929283e9013$e7a7867d-56e3-4524-b3c2-5fcf6dc7c6f8$091b39ce-ca5f-41df-8bd7-a672db2363a7$537840b2-81d4-4c2a-ab2d-9b6825432f98$81f9d9a8-c138-417d-b90b-89b56d54be16$9117b3c6-80af-463d-8e4d-a35bef1023ac$67abc344-0920-44cc-87e0-a582c8976ff9$c1a949d5-adb4-444c-be32-b8904a49d198$b5e0e0cb-3adb-4f2f-a231-170ddc1ee6aapublished_objectsnbpkginstall_time_nsEinstantiatedòinstalled_versionsDatesstdlibLoggingExtras1.1.0terminal_outputsDates@
[0m[1mResolving...[22m
[90m===[39m
[32m[1m  No Changes[22m[39m to `/tmp/jl_pfhNN6/Project.toml`
[32m[1m  No Changes[22m[39m to `/tmp/jl_pfhNN6/Manifest.toml`

[0m[1mInstantiating...[22m
[90m===[39m

[0m[1mPrecompiling...[22m
[90m===[39m
[32m[1m  Activating[22m[39m project at `/tmp/jl_pfhNN6`nbpkg_sync@
[0m[1mResolving...[22m
[90m===[39m
[32m[1m  No Changes[22m[39m to `/tmp/jl_pfhNN6/Project.toml`
[32m[1m  No Changes[22m[39m to `/tmp/jl_pfhNN6/Manifest.toml`

[0m[1mInstantiating...[22m
[90m===[39m

[0m[1mPrecompiling...[22m
[90m===[39m
[32m[1m  Activating[22m[39m project at `/tmp/jl_pfhNN6`LoggingExtras@
[0m[1mResolving...[22m
[90m===[39m
[32m[1m  No Changes[22m[39m to `/tmp/jl_pfhNN6/Project.toml`
[32m[1m  No Changes[22m[39m to `/tmp/jl_pfhNN6/Manifest.toml`

[0m[1mInstantiating...[22m
[90m===[39m

[0m[1mPrecompiling...[22m
[90m===[39m
[32m[1m  Activating[22m[39m project at `/tmp/jl_pfhNN6`enabled÷restart_recommended_msgrestart_required_msgbusy_packageswaiting_for_permission,waiting_for_permission_but_probably_disabled«cell_inputs $e1be3bfb-0764-435d-872f-e073ca3c3ee8cell_id$e1be3bfb-0764-435d-872f-e073ca3c3ee8codeُbegin
	@error "This is an error message"
	@warn "This is a warn message"
	@info "This is an info message"
	@debug "This is a debug message"
endmetadatashow_logsèdisabled®skip_as_script«code_folded$9117b3c6-80af-463d-8e4d-a35bef1023accell_id$9117b3c6-80af-463d-8e4d-a35bef1023accode٘md"""
## TransformerLogger
This allows to transform the log received, not just the log message. A nice example is to add the time to the log message
"""metadatashow_logsèdisabled®skip_as_script«code_folded$57e26ae6-3972-4d86-8f66-0932192139fccell_id$57e26ae6-3972-4d86-8f66-0932192139fccodemd"""
## TeeLogger
There are many Loggers defined in `LoggingExtras` and we probably won't have time to go through all of them. Let's start with the `TeeLogger` or `demux`, this simply reroutes the log messages to different loggers. The interface of the constructor is:
```julia
TeeLogger(loggers::AbstractLogger...)
```
and the log message will be passed to all the loggers passed. A possible usage of it could be to print the debug messages in a different place respect to the info messages, in this way we would have a more clean space where we have only the imporant messages, and another place where we have detailed informations about the running code.
"""metadatashow_logsèdisabled®skip_as_script«code_folded$0dc51c5f-9a79-406a-ad52-5929283e9013cell_id$0dc51c5f-9a79-406a-ad52-5929283e9013codebegin
	logger = ActiveFilteredLogger(log->startswith(log.message,"I'm an unicorn"), current_logger())
	with_logger(logger) do
		@info "I'm an unicorn with a rainbow mantle" 	# this will be showed
		@info "I'm a bear" 	# this will not
	end
endmetadatashow_logsèdisabled®skip_as_script«code_folded$c1a949d5-adb4-444c-be32-b8904a49d198cell_id$c1a949d5-adb4-444c-be32-b8904a49d198codemd"""
## FileLogger
This logs to a file, let's see a more complex exampl combining the previous types

```julia-repl
julia> using LoggingExtras;

julia> demux_logger = TeeLogger(
    MinLevelLogger(FileLogger("info.log"), Logging.Info),
    MinLevelLogger(FileLogger("warn.log"), Logging.Warn),
);


julia> with_logger(demux_logger) do
    	@warn("It is bad")
    	@info("normal stuff")
    	@error("THE WORSE THING")
    	@debug("it is chill")
	end

shell>  cat warn.log
┌ Warning: It is bad
└ @ Main REPL[34]:2
┌ Error: THE WORSE THING
└ @ Main REPL[34]:4

shell>  cat info.log
┌ Warning: It is bad
└ @ Main REPL[34]:2
┌ Info: normal stuff
└ @ Main REPL[34]:3
┌ Error: THE WORSE THING
└ @ Main REPL[34]:4
```
"""metadatashow_logsèdisabled®skip_as_script«code_folded$cd7d1a77-533c-4898-863b-6f4030666886cell_id$cd7d1a77-533c-4898-863b-6f4030666886codeusing LoggingExtrasmetadatashow_logsèdisabled®skip_as_script«code_folded$81f9d9a8-c138-417d-b90b-89b56d54be16cell_id$81f9d9a8-c138-417d-b90b-89b56d54be16codebegin
	error_only_logger = MinLevelLogger(current_logger(), Logging.Error);
	with_logger(error_only_logger) do
           @info "You won't see this"
           @warn "won't see this either"
           @error "You will only see this"
    end
endmetadatashow_logsèdisabled®skip_as_script«code_folded$d80331e9-f2c9-4689-9c87-125d7082e7a9cell_id$d80331e9-f2c9-4689-9c87-125d7082e7a9codelet
	function foo1()
		@error "This is an error with an exception and a backtrace" exception=(ArgumentError("something"), backtrace())
		@info "This will be shown since we haven't trhown the error"
	end
	foo1()
endmetadatashow_logsèdisabled®skip_as_script«code_folded$e7a7867d-56e3-4524-b3c2-5fcf6dc7c6f8cell_id$e7a7867d-56e3-4524-b3c2-5fcf6dc7c6f8code	md"""
!!! note
	Pluto doesn't allow to set the global logger since each cell is evaluated with a different logger, but the function `global_logger([logger])` returns the current global logger, and if a logger is passed as argument, the global logger is changed.
"""metadatashow_logsèdisabled®skip_as_script«code_folded$ca6dd602-d5d6-496d-9711-783925d39764cell_id$ca6dd602-d5d6-496d-9711-783925d39764codealet
	A = [1, 2, 3]
	@info "This is an info message" A
	@info "you can also use keyword" var=A
endmetadatashow_logsèdisabled®skip_as_script«code_folded$9d3649bc-7a6f-4106-94ff-b10fe0f6ecd7cell_id$9d3649bc-7a6f-4106-94ff-b10fe0f6ecd7codelet
	function foo2()
		ex = ArgumentError("something")
		@error "This is an error with an exception and a backtrace" exception=(ex, backtrace())
		throw(ex)
		@info "This will not be shown"
	end
	foo2()
endmetadatashow_logsèdisabled®skip_as_script«code_folded$537840b2-81d4-4c2a-ab2d-9b6825432f98cell_id$537840b2-81d4-4c2a-ab2d-9b6825432f98codeٛmd"""
## MinLevelLogger
This is a special case of the early filtered logger that checks if the message level is above the level specified when created.
"""metadatashow_logsèdisabled®skip_as_script«code_folded$4b3aa5b4-0b71-46b4-aaa4-c038e7abb998cell_id$4b3aa5b4-0b71-46b4-aaa4-c038e7abb998codeqmd"""
## ActiveFilteredLogger
This allows to only select some log messages to show based on a filter function
"""metadatashow_logsèdisabled®skip_as_script«code_folded$091b39ce-ca5f-41df-8bd7-a672db2363a7cell_id$091b39ce-ca5f-41df-8bd7-a672db2363a7codeNmd"""
### EarlyFilteredLogger
This is similar to the `ActiveFilteredLogger` but the filter function is called before the log message is generated so the filter cannot be based on it, but it can still access:
- `level` the level of the log
- `module` which module called the logger
- `id` this is a unique identifier of the message
"""metadatashow_logsèdisabled®skip_as_script«code_folded$40fea74a-0f17-11f0-2c2c-d356a1a2b91dcell_id$40fea74a-0f17-11f0-2c2c-d356a1a2b91dcodeVmd"""
# Logging
Logging is very important when writing code, logged messages are used to track the execution of the program, also allowing to more simply identify bugs and debug them.

Julia has two main libraries for logging, the base one `Logging` and an extended version `LoggingExtras`.

The main types of logging are:
- Error
- Warn
- Info
- Debug

We can decide which is the minimul level to log, the important thing is that the code below that thersold will not get executed, this allows to mark as debug some expensive checks that we want to perform only when we are performing a debug.
"""metadatashow_logsèdisabled®skip_as_script«code_folded$67abc344-0920-44cc-87e0-a582c8976ff9cell_id$67abc344-0920-44cc-87e0-a582c8976ff9codeQbegin
	using Dates
	const date_format = "yyyy-mm-dd HH:MM:SS"

	timestamp_logger(logger) =
    	TransformerLogger(logger) do log
        	merge(log, (; message="[$(Dates.format(now(), date_format))] $(log.message)"))
    	end
	with_logger(current_logger() |> timestamp_logger) do
		@info "The time will be added to this message"
	end
endmetadatashow_logsèdisabled®skip_as_script«code_folded$4e0636a1-ac8f-4394-8afe-ecf00a2835dacell_id$4e0636a1-ac8f-4394-8afe-ecf00a2835dacodemd"""
We can also add an exception and a backtrace to the `@error` macro, it is important to know that the exception would not be thrown automatically. This allows to know if an error occurred by reading the log even if the error was catched.
"""metadatashow_logsèdisabled®skip_as_script«code_folded$8df6d668-11a0-4ed3-82e6-eeaa833bdf1ecell_id$8df6d668-11a0-4ed3-82e6-eeaa833bdf1ecodeٜmd"""
## Log a message
To log a message, we just need to use the macros `@error`, `@warn`, `@info` and `@debug`, followed by the message we wish to show
"""metadatashow_logsèdisabled®skip_as_script«code_folded$b5e0e0cb-3adb-4f2f-a231-170ddc1ee6aacell_id$b5e0e0cb-3adb-4f2f-a231-170ddc1ee6aacodemd"""
This is the usual setup I use in my own code:
```julia
using LoggingExtras, Dates

const date_format = "yyyy-mm-dd HH:MM:SS"

timestamp_logger(logger) =
    TransformerLogger(logger) do log
        merge(log, (; message="[$(Dates.format(now(), date_format))] $(log.message)"))
    end

demux_logger(infoFileName::AbstractString, debugFileName::AbstractString) = TeeLogger(
    MinLevelLogger(FileLogger("$infoFileName.info.log"; append=true), Logging.Info),
    MinLevelLogger(FileLogger("$debugFileName.debug.log"; append=true), Logging.Debug),
);
demux_logger(str::AbstractString) = demux_logger(str, str)

demux_logger(joinpath(folder_name, baseFilename)) |> timestamp_logger |> global_logger
```
"""metadatashow_logsèdisabled®skip_as_script«code_folded$950186f6-1cb1-480d-9898-1033a7fa86d2cell_id$950186f6-1cb1-480d-9898-1033a7fa86d2codezmd"""
we can also add variables to it that will be shown togheter with the message, this is very useful when debugging
"""metadatashow_logsèdisabled®skip_as_script«code_foldedënotebook_id$fa683adc-2f05-11f0-0906-ef0e3f12cda9in_temp_dir¨metadata