Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Made LogRecordData keys parametric, rather than being restricted to Symbols #5

Merged
merged 1 commit into from
Apr 23, 2024
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
7 changes: 7 additions & 0 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,17 @@ version = "1.0.2"
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
Dictionaries = "85a47980-9c8c-11e8-2b9f-f7ca1fa99fb4"
Distributed = "8ba89e20-285c-5b6f-9357-94700520ee1b"
ForwardMethods = "5fe2550f-d27e-4649-9aea-fdf9a83a1aa9"
InternedStrings = "7d512f48-7fb1-5a58-b986-67e6dc259f01"
Logging = "56ddb016-857b-54e1-b83d-db4d58db5568"
PrecompileTools = "aea7be01-6a6a-4083-8856-8a6e6704d82a"

[compat]
Dates = "1"
Dictionaries = "0.3, 0.4"
Distributed = "1"
ForwardMethods = "1.6"
InternedStrings = "0.7"
Logging = "1"
PrecompileTools = "1"
julia = "1.6"
4 changes: 2 additions & 2 deletions src/LoggingCommon.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module LoggingCommon

using Dates, Dictionaries, Distributed, Logging, PrecompileTools
using Dates, Dictionaries, Distributed, ForwardMethods, Logging, InternedStrings, PrecompileTools

# Log levels
export NotSet, All, Trace,Notice, Critical, Alert, Emergency, Fatal, AboveMax, Off
Expand All @@ -19,7 +19,7 @@ module LoggingCommon

export AbstractLogRecord, LogRecord, MessageLogRecord, StacktraceLogRecord

export message_log_record, stacktrace_log_record
export message_log_record, stacktrace_log_record, add_record_data!

export log_record_data, static_metadata, runtime_metadata, is_error_record

Expand Down
2 changes: 1 addition & 1 deletion src/levels.jl
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ end

NamedLogLevel(l::NamedLogLevel) = l

Base.string(l::NamedLogLevel) = string(l.name)
Base.string(l::NamedLogLevel) = intern(string(l.name))

log_level(l::NamedLogLevel) = symbol_to_log_levels[l.name]

Expand Down
89 changes: 60 additions & 29 deletions src/records.jl
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
function module_str_trim_main(_module::Module)
name = fullname(_module)
if first(name) == :Main && length(name) > 1
return join(name[2:end], '.')
return join(view(name, 2:length(name)), '.')
else
return join(name, '.')
end
Expand Down Expand Up @@ -31,13 +31,14 @@ function StaticLogRecordMetadata(source::AbstractString, level::LogLevel, level_
return StaticLogRecordMetadata(string(source), level, level_name, something(filename, "?"), line_num, group, id)
end

StaticLogRecordMetadata(source::AbstractString, level, lnn::LineNumberNode, args...) = StaticLogRecordMetadata(source, level, "", _filename(lnn), lnn.line, args...)
StaticLogRecordMetadata(source::AbstractString, level::LogLevel, lnn::LineNumberNode, args...) = StaticLogRecordMetadata(source, level, intern(""), _filename(lnn), lnn.line, args...)

StaticLogRecordMetadata(source::AbstractString, level::LogLevel, filename::Union{LineNumberNode, String, Nothing}, line_num::Union{LineNumberNode, Int}, args...) = StaticLogRecordMetadata(source, level, string(nearest_log_level(level)), filename, line_num, args...)
StaticLogRecordMetadata(source::AbstractString, level::LogLevel, filename::Union{String, Nothing}, line_num::Union{LineNumberNode, Int}, args...) = StaticLogRecordMetadata(source, level, string(nearest_log_level(level)), filename, line_num, args...)

StaticLogRecordMetadata(source::AbstractString, level::NamedLogLevel, args...) = StaticLogRecordMetadata(source, log_level(level), string(level), args...)

StaticLogRecordMetadata(source::Module, args...) = StaticLogRecordMetadata(module_str_trim_main(source), args...)

StaticLogRecordMetadata(source::Module, args...) = StaticLogRecordMetadata(intern(module_str_trim_main(source)), args...)

"""
RuntimeLogRecordMetadata(datetime::DateTime, thread_id::Int, worker_id::Int)
Expand All @@ -59,34 +60,61 @@ end
"""
LogRecordData(data)

LogRecordData(args::Pair{Symbol, <:Any}...)
LogRecordData(args::Pair{<:Any, <:Any}...)

A type representing an optional collection of `key => value` pairs attached to a log record.

A type representing an optional collection of `key => value` pairs attached to a log record.
`data` must be an iterable collection where each element is a `Pair`
"""
struct LogRecordData
data::Union{Nothing,Vector{Pair{Symbol, Any}}}
function LogRecordData(d; exclude::Union{Symbol,Vector{Symbol}}=Symbol[])
if !isnothing(d) && !isempty(d)
_exclude = exclude isa Symbol ? [exclude] : exclude
return new([convert(Pair{Symbol,Any}, di) for di in d if first(di) ∉ _exclude])
else
return new(nothing)
end
end
struct LogRecordData{K}
data::Dictionary{K, Any}
LogRecordData{K}() where {K} = new(Dictionary{K, Any}())
end
Base.isempty(l::LogRecordData) = isnothing(l.data) || isempty(l.data)
Base.length(l::LogRecordData) = isnothing(l.data) ? 0 : length(l.data)
Base.pairs(l::LogRecordData) = isnothing(l.data) ? pairs((;)) : l.data
Base.iterate(l::LogRecordData) = isnothing(l.data) ? nothing : iterate(l.data)
Base.iterate(l::LogRecordData, st) = isnothing(st) ? nothing : iterate(l.data, st)

function LogRecordData(args::Pair{Symbol, <:Any}...)
if !isempty(args)
return LogRecordData(collect(args))
else
return LogRecordData(nothing)
@forward_methods LogRecordData field=data Base.isempty(_) Base.length(_) Base.pairs(_)
Base.eltype(::Type{LogRecordData{K}}) where {K} = Pair{K, Any}
Base.iterate(d::LogRecordData) = iterate(pairs(d.data))
Base.iterate(d::LogRecordData, st) = iterate(pairs(d.data), st)
Base.collect(d::LogRecordData) = collect(pairs(d.data))

"""
add_record_data!(r, data::Pair)

Adds the `data := key => value` pair to `r`
"""
add_record_data!(d::LogRecordData{K}, data::Pair{K, <:Any}) where {K} = (set!(d.data, first(data), last(data)); nothing)

add_record_data!(d::LogRecordData{K}, data::Pair) where {K} = add_record_data!(d, convert(K, first(data))::K => last(data))

function _log_record_data(kv_pairs, T; exclude=())
d = LogRecordData{T}()
_exclude = (exclude isa Tuple || exclude isa Vector) ? exclude : (exclude,)
for (k, v) in kv_pairs
if k ∉ _exclude
set!(d.data, k, v)
end
end
return d
end
key_type(::Type{Pair{K, V}}) where {K, V} = K

"""
log_record_data(kv_pairs; [exclude=()]) -> LogRecordData

Returns a `LogRecordData` from the input `key => value` pairs
"""
log_record_data(kv_pairs; exclude=()) = _log_record_data(kv_pairs, mapfoldl(key_type ∘ typeof, promote_type, kv_pairs; init=Union{}); exclude)

"""
log_record_data() -> LogRecordData{Symbol}

"""
log_record_data() = _log_record_data((), Symbol)

LogRecordData(::Nothing; kwargs...) = _log_record_data((), Symbol; kwargs...)
LogRecordData(data; kwargs...) = log_record_data(data; kwargs...)
LogRecordData(args::Pair{Symbol, <:Any}...; kwargs...) = _log_record_data(args, Symbol; kwargs...)



"""
AbstractLogRecord
Expand All @@ -98,7 +126,7 @@ abstract type AbstractLogRecord end
"""
log_record_data(record)

Returns the `key` => `value` pairs associated with `record`
Returns an iterator over the `key` => `value` pairs associated with `record`
"""
log_record_data(::AbstractLogRecord) = nothing

Expand Down Expand Up @@ -155,6 +183,9 @@ struct LogRecord{R} <: AbstractLogRecord
data::LogRecordData
record::R
end
@forward_methods LogRecord field=data add_record_data!(_, data)

Base.propertynames(::LogRecord{R}) where {R} = (fieldnames(LogRecord)..., fieldnames(R)...)

function Base.getproperty(l::LogRecord, name::Symbol)
if name === :static_meta || name === :runtime_meta || name === :data || name === :record
Expand All @@ -166,7 +197,7 @@ end

LogRecord(static_meta::StaticLogRecordMetadata, runtime_meta::RuntimeLogRecordMetadata, record::AbstractLogRecord, data::LogRecordData) = LogRecord{typeof(record)}(static_meta, runtime_meta, data, record)

LogRecord(static_meta::StaticLogRecordMetadata, runtime_meta::RuntimeLogRecordMetadata, record::AbstractLogRecord, args::Pair{Symbol, <:Any}...) = LogRecord(static_meta, runtime_meta, record, LogRecordData(args...))
LogRecord(static_meta::StaticLogRecordMetadata, runtime_meta::RuntimeLogRecordMetadata, record::AbstractLogRecord, args::Pair{<:Any, <:Any}...) = LogRecord(static_meta, runtime_meta, record, LogRecordData(args...))

LogRecord(static_meta::StaticLogRecordMetadata, record::AbstractLogRecord, args...; runtime_meta::RuntimeLogRecordMetadata=RuntimeLogRecordMetadata()) = LogRecord(static_meta, runtime_meta, record, args...)

Expand Down
6 changes: 5 additions & 1 deletion test/Project.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
[deps]
Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
TestingUtilities = "40452611-1178-4e48-bdfc-3af4bebad9c9"
TestingUtilities = "40452611-1178-4e48-bdfc-3af4bebad9c9"

[compat]
Aqua = "0.8"
23 changes: 14 additions & 9 deletions test/TestLoggingCommon.jl
Original file line number Diff line number Diff line change
Expand Up @@ -73,30 +73,30 @@ module TestLoggingCommon
end
@testset "LogRecordData" begin
d = LogRecordData()
@Test isnothing(d.data)
@Test isnothing(Base.iterate(d))
@Test isempty(Base.pairs(d))
@Test isempty(d)
@Test length(d) == 0
d = LogRecordData(:a => 1)
@Test d.data == [:a => 1]
@Test Base.pairs(d) == d.data
@Test Base.iterate(d) == (:a => 1, 2)
@Test Base.iterate(d, 2) |> isnothing
@Test Base.pairs(d) |> collect == [:a => 1]
@Test Base.iterate(d) == (:a => 1, 1)
@Test Base.iterate(d, 1) |> isnothing
@Test !isempty(d)
@Test length(d) == 1

d = LogRecordData(:a => 1, :b => String)
@Test length(d) == 2
for (i, (k,v)) in enumerate(d)
if i == 1
@test k == :a
@test v == 1
@Test k == :a
@Test v == 1
else
@test k == :b
@test v == String
@Test k == :b
@Test v == String
end
end
d = log_record_data(("a" => 1, "b" => 2); exclude="a")
@Test collect(d) == ["b" => 2]
end
@testset "message_log_record" begin
static = StaticLogRecordMetadata(Main, NamedLogLevel(:info), "a.jl", 1, "group", "id")
Expand All @@ -109,6 +109,11 @@ module TestLoggingCommon
@test !is_error_record(record)
@test isempty(log_record_data(record))

add_record_data!(record, :a => "1")
@Test log_record_data(record) |> collect == [:a => "1"]
add_record_data!(record, :b => true)
@Test log_record_data(record) |> collect == [:a => "1", :b => true]

static = StaticLogRecordMetadata(Main, NamedLogLevel(:error), "a.jl", 1, "group", "id")
record = message_log_record(static, "Error message", :a => 1, :b => String)
@test static_metadata(record) == static
Expand Down
7 changes: 7 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
using Test

using LoggingCommon

if VERSION ≥ v"1.9"
using Aqua
Aqua.test_all(LoggingCommon)
end

include("TestLoggingCommon.jl")
Loading