Skip to content

Commit 81c23a1

Browse files
committed
some progress
1 parent 2d740b8 commit 81c23a1

2 files changed

Lines changed: 130 additions & 4 deletions

File tree

src/interface/interface.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,14 @@ All keyword arguments are passed to the [`initialize_state!`](@ref)`(problem, al
4444
"""
4545
function solve!(problem::Problem, algorithm::Algorithm, state::State; kwargs...)
4646
initialize_state!(problem, algorithm, state; kwargs...)
47-
log_start!(problem, algorithm, state)
47+
log!(problem, algorithm, state; context = :Start)
4848
while !is_finished!(problem, algorithm, state)
49-
log_before_iteration!(problem, algorithm, state)
49+
log!(problem, algorithm, state; context = :PreStep)
5050
increment!(state)
5151
step!(problem, algorithm, state)
52-
log_after_iteration!(problem, algorithm, state)
52+
log!(problem, algorithm, state; context = :PostStep)
5353
end
54-
log_stop!(problem, algorithm, state)
54+
log!(problem, algorithm, state; context = :Stop)
5555
return state
5656
end
5757

src/logging.jl

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,127 @@
1+
"""
2+
log!(problem::Problem, algorithm::Algorithm, state::State; context::Symbol) -> nothing
13
4+
Generate a log record for the given `(problem, algorithm, state)`, using the logging action associated to `context`.
5+
By default, the following events trigger a logging action with the given `context`:
6+
7+
| context | event |
8+
| --------- | ------------------------------------- |
9+
| :Start | The solver has been initialized. |
10+
| :PreStep | The solver is about to take a step. |
11+
| :PostStep | The solver has taken a step. |
12+
| :Stop | The solver has finished. |
13+
14+
Specific algorithms can associate other events with other contexts.
15+
16+
See also [`register_action!`](@ref) to associate custom actions with these contexts.
17+
"""
18+
function log!(problem::Problem, algorithm::Algorithm, state::State; context)::Nothing
19+
action = @something(logging_action(problem, algorithm, state, context), return nothing)
20+
# TODO: filter out `nothing` logdata
21+
@logmsg(
22+
loglevel(action), logdata!(action, problem, algorithm, state),
23+
_id = logid(action), _group = loggroup(algorithm)
24+
)
25+
return nothing
26+
end
27+
28+
"""
29+
logging_action(problem::Problem, algorithm::Algorithm, state::State, context::Symbol)
30+
-> Union{Nothing,LoggingAction}
31+
32+
Obtain the registered logging action associated to an event identified by `context`.
33+
The default implementation assumes a dictionary-like object `state.logging_action`, which holds
34+
the different registered actions.
35+
"""
36+
function logging_action(::Problem, ::Algorithm, state::State, context::Symbol)
37+
return get(state.logging_actions, context, nothing)
38+
end
39+
40+
@doc """
41+
loggroup(algorithm::Algorithm) -> Symbol
42+
loggroup(::Type{<:Algorithm}) -> Symbol
43+
44+
Generate a group id to attach to all log records for a given algorithm.
45+
""" loggroup
46+
47+
loggroup(algorithm::Algorithm) = loggroup(typeof(algorithm))
48+
loggroup(Alg::Type{<:Algorithm}) = Base.nameof(Alg)
49+
50+
# Sources
51+
# -------
52+
"""
53+
LoggingAction
54+
55+
Abstract supertype for defining an action that generates a log record.
56+
57+
## Methods
58+
Any concrete subtype should at least implement the following method:
59+
- [`logdata!(action, problem, algorithm, state)`](@ref logdata!) : generate the data for the log record.
60+
61+
Addionally, the following methods can be specialized to alter the default behavior:
62+
- [`loglevel(action) = Logging.Info`](@ref loglevel) : specify the logging level of the generated record.
63+
- [`logid(action) = objectid(action)`](@ref logid) : specify a unique identifier to associate with the record.
64+
"""
65+
abstract type LoggingAction end
66+
67+
logdata!(::LoggingAction, ::Problem, ::Algorithm, ::State) = missing
68+
loglevel(::LoggingAction) = Logging.Info
69+
logid(action::LoggingAction) = objectid(action)
70+
71+
struct LogCallback{F} <: LoggingAction
72+
f::F
73+
end
74+
75+
logdata!(action::LogCallback, problem, algorithm, state) =
76+
action.f(problem, algorithm, state)
77+
78+
struct LogGroup{A <: LoggingAction} <: LoggingAction
79+
actions::Vector{A}
80+
end
81+
82+
loglevel(alg::LogGroup) = maximum(loglevel, alg.actions)
83+
84+
logdata!(action::LogGroup, problem, algorithm, state) = map(action.actions) do action
85+
return logdata!(action, problem, algorithm, state)
86+
end
87+
88+
struct LogLvl{F, A <: LoggingAction} <: LoggingAction
89+
action::A
90+
lvl::LogLevel
91+
end
92+
93+
loglevel(alg::LogLvl) = alg.lvl
94+
95+
struct LogIf{F, A <: LoggingAction} <: LoggingAction
96+
predicate::F
97+
action::A
98+
end
99+
100+
# first cheap check through the level
101+
loglevel(alg::LogIf) = loglevel(alg.action)
102+
103+
# second check through the predicate
104+
logdata!(action::LogIf, problem::Problem, algorithm::Algorithm, state::State) =
105+
action.predicate(problem, algorithm, state) ? logdata!(action.action, problem, algorithm, state) : nothing
106+
107+
# Sinks
108+
# -----
109+
struct StringFormat{F <: PrintF.Format}
110+
format::F
111+
end
112+
function (formatter::StringFormat)(io::IO, lvl, msg, _module, group, id, file = nothing, line = nothing; indent::Integer = 0, kwargs...)
113+
iob = IOBuffer()
114+
return ioc = IOContext(iob, io)
115+
116+
end
117+
118+
struct FormatterGroup{K, V}
119+
rules::Dict{K, V}
120+
end
121+
122+
function (formatter::AlgorithmFormatter)(io::IO, log)
123+
rule = get(formatter.rules, log.id, nothing)
124+
isnothing(rule) ? println(io, log) :
125+
rule(io, log.level, log.message, log._module, log.group, log.id, log.file, log.line; log.kwargs...)
126+
return nothing
127+
end

0 commit comments

Comments
 (0)