Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Manifest.toml
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ git-tree-sha1 = "82921f0e3bde6aebb8e524efc20f4042373c0c06"
uuid = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09"
version = "0.5.2"


[[Markdown]]
deps = ["Base64"]
uuid = "d6f4376e-aef5-505a-96c1-9c027394607a"
Expand Down
2 changes: 2 additions & 0 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ CUDAdrv = "c5f51814-7f29-56b8-a69c-e4d8f6be1fde"
CUDAnative = "be33ccc6-a3ff-5ff2-a52e-74243cff1e17"
Cassette = "7057c7e9-c182-5462-911a-8362d720325c"
CuArrays = "3a865a2d-5b23-5a0f-bc46-62713ec82fae"
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
Distributed = "8ba89e20-285c-5b6f-9357-94700520ee1b"
FFTW = "7a1cc6ca-52ef-59f5-83cd-3a7055c09341"
GPUifyLoops = "ba82f77b-6841-5d2e-bd9f-4daf811aec27"
JLD2 = "033835bb-8acc-5ee8-8aae-3f567f8a3819"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
Logging = "56ddb016-857b-54e1-b83d-db4d58db5568"
NCDatasets = "85f8d34a-cbdd-5861-8df4-14fed0d494ab"
OffsetArrays = "6fe1bfb0-de20-5000-8ca7-80f57d26f881"
OrderedCollections = "bac558e1-5e72-5ebc-8fee-abe8a469f55d"
Expand Down
6 changes: 6 additions & 0 deletions src/Oceananigans.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ export
# Architectures
CPU, GPU,

# Logging
ModelLogger, Diagnostic, Setup, Simulation,

# Constants
second, minute, hour, day,

Expand Down Expand Up @@ -238,6 +241,8 @@ function TimeStepper end
function run_diagnostic end
function write_output end

using Logging

include("utils.jl")

include("clock.jl")
Expand All @@ -263,6 +268,7 @@ include("Solvers/Solvers.jl")
using .Solvers

include("forcing.jl")
include("logger.jl")
include("models.jl")

include("Diagnostics/Diagnostics.jl")
Expand Down
79 changes: 79 additions & 0 deletions src/logger.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
using Logging, Dates


####
#### Custom LogLevels
####
_custom_log_level_docs = """
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of curiousity, why assign the docstring to a variable?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Severity Order:
Debug < Diagnostic < Simulation < Setup < Info

Usage:
@logmsg Logging.LogLevel "Log Message"

@logmsg comes from Base/Logging
LogLevel can be any Base/Logging.LogLevel
Log Message can be any expression that evaluates to a string (preferably human readable!)
"""

const Diagnostic = Logging.LogLevel(-500) # Sits between Debug and Info
const Simulation = Logging.LogLevel(-250)
const Setup = Logging.LogLevel(-125)


####
#### ModelLogger
####
_model_logger_docs = """

ModelLogger(stream::IO, level::LogLevel)

Based on Logging.SimpleLogger it tries to log all messages in the following format

message --- [dd/mm/yyyy HH:MM:SS] log_level source_file:line_number

The logger will handle any message from Diagnostic up by default.
"""
struct ModelLogger <: Logging.AbstractLogger
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is the correct way to do this :-)

stream::IO
min_level::Logging.LogLevel
message_limits::Dict{Any,Int}
end
ModelLogger(stream::IO=stderr, level=Diagnostic) = ModelLogger(stream, level, Dict{Any,Int}())

Logging.shouldlog(logger::ModelLogger, level, _module, group, id) = get(logger.message_limits, id, 1) > 0

Logging.min_enabled_level(logger::ModelLogger) = logger.min_level

Logging.catch_exceptions(logger::ModelLogger) = false

function level_to_string(level::Logging.LogLevel)
if level == Diagnostic
"Diagnostic"
elseif level == Setup
"Setup"
elseif level == Logging.Warn
"Warning"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By the way, you will have noticed how this way of using custom levels isn't really composable, and doesn't really work well with the default ConsoleLogger provided by Base.

Here's my current attempt to clean up that situation (comments welcome): JuliaLang/julia#33960

else
string(level)
end
end

function Logging.handle_message(logger::ModelLogger, level, message, _module, group, id, filepath, line; maxlog = nothing, kwargs...)
if maxlog !== nothing && maxlog isa Integer
remaining = get!(logger.message_limits, id, maxlog)
logger.message_limits[id] = remaining - 1
remaining > 0 || return
end
buf = IOBuffer()
iob = IOContext(buf, logger.stream)
level_name = level_to_string(level)
module_name = something(_module, "nothing")
file_name = something(filepath, "nothing")
line_number = something(line, "nothing")
msg_timestamp = Dates.format(Dates.now(), "[dd/mm/yyyy HH:MM:SS]")
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is how the system is meant to be used :-)

As you have found out, you can get timestamps for every message in your application by customizing the logging backend rather than messing with the @info statements themselves.

formatted_message = "$message --- $msg_timestamp $level_name $file_name:$line_number"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀

println(iob, formatted_message)
write(logger.stream, take!(buf))
return nothing
end