• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

JuliaLang / julia / #37477

pending completion
#37477

push

local

web-flow
Allow external lattice elements to properly union split (#49030)

Currently `MustAlias` is the only lattice element that is allowed
to widen to union types. However, there are others in external
packages. Expand the support we have for this in order to allow
union splitting of lattice elements.

Co-authored-by: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com>

26 of 26 new or added lines in 5 files covered. (100.0%)

71476 of 82705 relevant lines covered (86.42%)

34756248.54 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

91.21
/stdlib/Logging/src/ConsoleLogger.jl
1
# This file is a part of Julia. License is MIT: https://julialang.org/license
2

3
"""
4
    ConsoleLogger([stream,] min_level=Info; meta_formatter=default_metafmt,
5
                  show_limited=true, right_justify=0)
6

7
Logger with formatting optimized for readability in a text console, for example
8
interactive work with the Julia REPL.
9

10
Log levels less than `min_level` are filtered out.
11

12
Message formatting can be controlled by setting keyword arguments:
13

14
* `meta_formatter` is a function which takes the log event metadata
15
  `(level, _module, group, id, file, line)` and returns a color (as would be
16
  passed to printstyled), prefix and suffix for the log message.  The
17
  default is to prefix with the log level and a suffix containing the module,
18
  file and line location.
19
* `show_limited` limits the printing of large data structures to something
20
  which can fit on the screen by setting the `:limit` `IOContext` key during
21
  formatting.
22
* `right_justify` is the integer column which log metadata is right justified
23
  at. The default is zero (metadata goes on its own line).
24
"""
25
struct ConsoleLogger <: AbstractLogger
26
    stream::IO
471✔
27
    min_level::LogLevel
28
    meta_formatter
29
    show_limited::Bool
30
    right_justify::Int
31
    message_limits::Dict{Any,Int}
32
end
33
function ConsoleLogger(stream::IO, min_level=Info;
50✔
34
                       meta_formatter=default_metafmt, show_limited=true,
35
                       right_justify=0)
36
    ConsoleLogger(stream, min_level, meta_formatter,
24✔
37
                  show_limited, right_justify, Dict{Any,Int}())
38
end
39
function ConsoleLogger(min_level=Info;
894✔
40
                       meta_formatter=default_metafmt, show_limited=true,
41
                       right_justify=0)
42
    ConsoleLogger(closed_stream, min_level, meta_formatter,
447✔
43
                  show_limited, right_justify, Dict{Any,Int}())
44
end
45

46

47
shouldlog(logger::ConsoleLogger, level, _module, group, id) =
9✔
48
    get(logger.message_limits, id, 1) > 0
49

50
min_enabled_level(logger::ConsoleLogger) = logger.min_level
452✔
51

52
# Formatting of values in key value pairs
53
showvalue(io, msg) = show(io, "text/plain", msg)
5✔
54
function showvalue(io, e::Tuple{Exception,Any})
2✔
55
    ex,bt = e
2✔
56
    showerror(io, ex, bt; backtrace = bt!==nothing)
2✔
57
end
58
showvalue(io, ex::Exception) = showerror(io, ex)
1✔
59

60
function default_logcolor(level::LogLevel)
×
61
    level < Info  ? Base.debug_color() :
31✔
62
    level < Warn  ? Base.info_color()  :
63
    level < Error ? Base.warn_color()  :
64
                    Base.error_color()
65
end
66

67
function default_metafmt(level::LogLevel, _module, group, id, file, line)
16✔
68
    @nospecialize
×
69
    color = default_logcolor(level)
31✔
70
    prefix = string(level == Warn ? "Warning" : string(level), ':')
24✔
71
    suffix::String = ""
16✔
72
    Info <= level < Warn && return color, prefix, suffix
16✔
73
    _module !== nothing && (suffix *= string(_module)::String)
10✔
74
    if file !== nothing
10✔
75
        _module !== nothing && (suffix *= " ")
8✔
76
        suffix *= contractuser(file)::String
8✔
77
        if line !== nothing
8✔
78
            suffix *= ":$(isa(line, UnitRange) ? "$(first(line))-$(last(line))" : line)"
7✔
79
        end
80
    end
81
    !isempty(suffix) && (suffix = "@ " * suffix)
10✔
82
    return color, prefix, suffix
10✔
83
end
84

85
# Length of a string as it will appear in the terminal (after ANSI color codes
86
# are removed)
87
function termlength(str)
25✔
88
    N = 0
×
89
    in_esc = false
×
90
    for c in str
49✔
91
        if in_esc
348✔
92
            if c == 'm'
×
93
                in_esc = false
×
94
            end
95
        else
96
            if c == '\e'
348✔
97
                in_esc = true
×
98
            else
99
                N += 1
348✔
100
            end
101
        end
102
    end
672✔
103
    return N
25✔
104
end
105

106
function handle_message(logger::ConsoleLogger, level::LogLevel, message, _module, group, id,
53✔
107
                        filepath, line; kwargs...)
108
    @nospecialize
1✔
109
    hasmaxlog = haskey(kwargs, :maxlog) ? 1 : 0
26✔
110
    maxlog = get(kwargs, :maxlog, nothing)
48✔
111
    if maxlog isa Core.BuiltinInts
26✔
112
        remaining = get!(logger.message_limits, id, Int(maxlog)::Int)
8✔
113
        logger.message_limits[id] = remaining - 1
4✔
114
        remaining > 0 || return
5✔
115
    end
116

117
    # Generate a text representation of the message and all key value pairs,
118
    # split into lines.
119
    msglines = [(indent=0, msg=l) for l in split(chomp(convert(String, string(message))::String), '\n')]
25✔
120
    stream::IO = logger.stream
25✔
121
    if !(isopen(stream)::Bool)
25✔
122
        stream = stderr
2✔
123
    end
124
    dsize = displaysize(stream)::Tuple{Int,Int}
25✔
125
    nkwargs = length(kwargs)::Int
25✔
126
    if nkwargs > hasmaxlog
25✔
127
        valbuf = IOBuffer()
5✔
128
        rows_per_value = max(1, dsize[1] รท (nkwargs + 1 - hasmaxlog))
5✔
129
        valio = IOContext(IOContext(valbuf, stream),
5✔
130
                          :displaysize => (rows_per_value, dsize[2] - 5),
131
                          :limit => logger.show_limited)
132
        for (key, val) in kwargs
10✔
133
            key === :maxlog && continue
7✔
134
            showvalue(valio, val)
7✔
135
            vallines = split(String(take!(valbuf)), '\n')
7✔
136
            if length(vallines) == 1
7✔
137
                push!(msglines, (indent=2, msg=SubString("$key = $(vallines[1])")))
3✔
138
            else
139
                push!(msglines, (indent=2, msg=SubString("$key =")))
4✔
140
                append!(msglines, ((indent=3, msg=line) for line in vallines))
4✔
141
            end
142
        end
9✔
143
    end
144

145
    # Format lines as text with appropriate indentation and with a box
146
    # decoration on the left.
147
    color, prefix, suffix = logger.meta_formatter(level, _module, group, id, filepath, line)::Tuple{Union{Symbol,Int},String,String}
25✔
148
    minsuffixpad = 2
1✔
149
    buf = IOBuffer()
25✔
150
    iob = IOContext(buf, stream)
25✔
151
    nonpadwidth = 2 + (isempty(prefix) || length(msglines) > 1 ? 0 : length(prefix)+1) +
44✔
152
                  msglines[end].indent + termlength(msglines[end].msg) +
153
                  (isempty(suffix) ? 0 : length(suffix)+minsuffixpad)
154
    justify_width = min(logger.right_justify, dsize[2])
25✔
155
    if nonpadwidth > justify_width && !isempty(suffix)
25✔
156
        push!(msglines, (indent=0, msg=SubString("")))
15✔
157
        minsuffixpad = 0
×
158
        nonpadwidth = 2 + length(suffix)
15✔
159
    end
160
    for (i, (indent, msg)) in enumerate(msglines)
50✔
161
        boxstr = length(msglines) == 1 ? "[ " :
222✔
162
                 i == 1                ? "โ”Œ " :
163
                 i < length(msglines)  ? "โ”‚ " :
164
                                         "โ”” "
165
        printstyled(iob, boxstr, bold=true, color=color)
115✔
166
        if i == 1 && !isempty(prefix)
115✔
167
            printstyled(iob, prefix, " ", bold=true, color=color)
24✔
168
        end
169
        print(iob, " "^indent, msg)
115✔
170
        if i == length(msglines) && !isempty(suffix)
115✔
171
            npad = max(0, justify_width - nonpadwidth) + minsuffixpad
19✔
172
            print(iob, " "^npad)
19✔
173
            printstyled(iob, suffix, color=:light_black)
19✔
174
        end
175
        println(iob)
115✔
176
    end
205✔
177

178
    write(stream, take!(buf))
25✔
179
    nothing
25✔
180
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc