Skip to content

Memento -> Logging - #312

Draft
rofinn wants to merge 4 commits into
JuliaDatabases:masterfrom
rofinn:rf/drop-memento
Draft

Memento -> Logging#312
rofinn wants to merge 4 commits into
JuliaDatabases:masterfrom
rofinn:rf/drop-memento

Conversation

@rofinn

@rofinn rofinn commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Replaces usage of the largely unmaintained Memento dependency for Logging.

NOTES

  • Unfortunately, this is technically a breaking change for any users who configure LibPQ logging via Memento. I suspect it'll need to be tagged as v2.0.0. If desired, I can scan the registry to see if any registered packages need updating.
  • The current tests fail on 1.12, so I chose to use 1.10 for all testing. getindex(::Column) seems to have some allocation changes on the newer Julia releases.
  • While the default log formatting will be different and configuration works differently, I've tried to keep the behaviour the same. For example, Memento.error would throw an error, but @error does not, so I've opted for @error sprint(showerror, err); throw(err).
  • Finally, there is some weirdness with a single doctest because we can no longer hide LibPQ logs globally in the make.jl because IOCapture does its own with_logger(ConsoleLogger(...)) that we don't have acces to.

Output

Below shows some of the REPL output before and after.

Before:

 julia +1.10 --project=.
               _
   _       _ _(_)_     |  Documentation: https://docs.julialang.org
  (_)     | (_) (_)    |
   _ _   _| |_  __ _   |  Type "?" for help, "]?" for Pkg help.
  | | | | | | |/ _` |  |
  | | |_| | | | (_| |  |  Version 1.10.11 (2026-03-09)
 _/ |\__'_|_|_|\__'_|  |  Official https://julialang.org/ release
|__/                   |

julia> using LibPQ

julia> LibPQ.Connection("host=localhost port=59999 connect_timeout=2")
[error | LibPQ]: connection to server at "localhost" (::1), port 59999 failed: Connection refused
        Is the server running on that host and accepting TCP/IP connections?
connection to server at "localhost" (127.0.0.1), port 59999 failed: Connection refused
        Is the server running on that host and accepting TCP/IP connections?
ERROR: connection to server at "localhost" (::1), port 59999 failed: Connection refused
        Is the server running on that host and accepting TCP/IP connections?
connection to server at "localhost" (127.0.0.1), port 59999 failed: Connection refused
        Is the server running on that host and accepting TCP/IP connections?
Stacktrace:
 [1] error(logger::Memento.Logger, exc::LibPQ.Errors.PQConnectionError)
   @ Memento ~/repos/invenia/Memento.jl/src/loggers.jl:463
 [2] handle_new_connection(jl_conn::LibPQ.Connection; throw_error::Bool)
   @ LibPQ ~/repos/invenia/LibPQ.jl/src/connections.jl:127
 [3] LibPQ.Connection(str::String; throw_error::Bool, connect_timeout::Int64, options::Dict{String, String}, kwargs::@Kwargs{})
   @ LibPQ ~/repos/invenia/LibPQ.jl/src/connections.jl:0
 [4] LibPQ.Connection(str::String)
   @ LibPQ ~/repos/invenia/LibPQ.jl/src/connections.jl:265
 [5] top-level scope
   @ REPL[2]:1

julia> LibPQ.Connection("host=localhost port=59999 connect_timeout=2"; throw_error=false);
[warn | LibPQ]: connection to server at "localhost" (::1), port 59999 failed: Connection refused
        Is the server running on that host and accepting TCP/IP connections?
connection to server at "localhost" (127.0.0.1), port 59999 failed: Connection refused
        Is the server running on that host and accepting TCP/IP connections?

julia> LibPQ.Connection("dbname='unterminated")
[error | LibPQ]: unterminated quoted string in connection info string
ERROR: unterminated quoted string in connection info string
Stacktrace:
 [1] error(logger::Memento.Logger, exc::LibPQ.Errors.ConninfoParseError)
   @ Memento ~/repos/invenia/Memento.jl/src/loggers.jl:463
 [2] conninfo(str::String)
   @ LibPQ ~/repos/invenia/LibPQ.jl/src/connections.jl:749
 [3] LibPQ.Connection(str::String; throw_error::Bool, connect_timeout::Int64, options::Dict{String, String}, kwargs::@Kwargs{})
   @ LibPQ ~/repos/invenia/LibPQ.jl/src/connections.jl:279
 [4] LibPQ.Connection(str::String)
   @ LibPQ ~/repos/invenia/LibPQ.jl/src/connections.jl:265
 [5] top-level scope
   @ REPL[4]:1

julia> conn = LibPQ.Connection("host=localhost dbname=postgres user=postgres password=password123");

julia> println("isopen(conn) = ", isopen(conn))
isopen(conn) = true

julia> result = execute(conn, "SELECT tablename FROM pg_catalog.pg_tables LIMIT 3;");

julia> println("result[1, 1] = ", result[1, 1])
result[1, 1] = pg_statistic

julia> close(result)

julia> execute(conn, "SELCET 1;")
[error | LibPQ]: SyntaxError: ERROR:  syntax error at or near "SELCET"
LINE 1: SELCET 1;
        ^
ERROR: SyntaxError: ERROR:  syntax error at or near "SELCET"
LINE 1: SELCET 1;
        ^
Stacktrace:
 [1] error(logger::Memento.Logger, exc::LibPQ.Errors.PQResultError{LibPQ.Errors.C42, LibPQ.Errors.E42601})
   @ Memento ~/repos/invenia/Memento.jl/src/loggers.jl:463
 [2] handle_result(jl_result::LibPQ.Result{false}; throw_error::Bool)
   @ LibPQ ~/repos/invenia/LibPQ.jl/src/results.jl:238
 [3] handle_result
   @ ~/repos/invenia/LibPQ.jl/src/results.jl:230 [inlined]
 [4] _multi_execute(jl_conn::LibPQ.Connection, query::String; throw_error::Bool, kwargs::@Kwargs{})
   @ LibPQ ~/repos/invenia/LibPQ.jl/src/results.jl:305
 [5] _multi_execute
   @ ~/repos/invenia/LibPQ.jl/src/results.jl:298 [inlined]
 [6] #execute#51
   @ ~/repos/invenia/LibPQ.jl/src/results.jl:294 [inlined]
 [7] execute(conn::LibPQ.Connection, query::String)
   @ LibPQ ~/repos/invenia/LibPQ.jl/src/results.jl:290
 [8] top-level scope
   @ REPL[10]:1

julia> execute(conn, "SELCET 1;"; throw_error=false);
[warn | LibPQ]: SyntaxError: ERROR:  syntax error at or near "SELCET"
LINE 1: SELCET 1;
        ^

julia> close(conn)

After:

 julia +1.10 --project=.
               _
   _       _ _(_)_     |  Documentation: https://docs.julialang.org
  (_)     | (_) (_)    |
   _ _   _| |_  __ _   |  Type "?" for help, "]?" for Pkg help.
  | | | | | | |/ _` |  |
  | | |_| | | | (_| |  |  Version 1.10.11 (2026-03-09)
 _/ |\__'_|_|_|\__'_|  |  Official https://julialang.org/ release
|__/                   |

julia> using LibPQ

julia> LibPQ.Connection("host=localhost port=59999 connect_timeout=2")
┌ Error: connection to server at "localhost" (::1), port 59999 failed: Connection refused
│       Is the server running on that host and accepting TCP/IP connections?
│ connection to server at "localhost" (127.0.0.1), port 59999 failed: Connection refused
│       Is the server running on that host and accepting TCP/IP connections?
└ @ LibPQ ~/repos/invenia/LibPQ.jl/src/connections.jl:127
ERROR: connection to server at "localhost" (::1), port 59999 failed: Connection refused
        Is the server running on that host and accepting TCP/IP connections?
connection to server at "localhost" (127.0.0.1), port 59999 failed: Connection refused
        Is the server running on that host and accepting TCP/IP connections?
Stacktrace:
 [1] handle_new_connection(jl_conn::LibPQ.Connection; throw_error::Bool)
   @ LibPQ ~/repos/invenia/LibPQ.jl/src/connections.jl:127
 [2] LibPQ.Connection(str::String; throw_error::Bool, connect_timeout::Int64, options::Dict{String, String}, kwargs::@Kwargs{})
   @ LibPQ ~/repos/invenia/LibPQ.jl/src/connections.jl:0
 [3] LibPQ.Connection(str::String)
   @ LibPQ ~/repos/invenia/LibPQ.jl/src/connections.jl:265
 [4] top-level scope
   @ REPL[2]:1

julia> LibPQ.Connection("host=localhost port=59999 connect_timeout=2"; throw_error=false);
┌ Warning: connection to server at "localhost" (::1), port 59999 failed: Connection refused
│       Is the server running on that host and accepting TCP/IP connections?
│ connection to server at "localhost" (127.0.0.1), port 59999 failed: Connection refused
│       Is the server running on that host and accepting TCP/IP connections?
└ @ LibPQ ~/repos/invenia/LibPQ.jl/src/connections.jl:129

julia> LibPQ.Connection("dbname='unterminated")
┌ Error: unterminated quoted string in connection info string
└ @ LibPQ ~/repos/invenia/LibPQ.jl/src/connections.jl:748
ERROR: unterminated quoted string in connection info string
Stacktrace:
 [1] conninfo(str::String)
   @ LibPQ ~/repos/invenia/LibPQ.jl/src/connections.jl:748
 [2] LibPQ.Connection(str::String; throw_error::Bool, connect_timeout::Int64, options::Dict{String, String}, kwargs::@Kwargs{})
   @ LibPQ ~/repos/invenia/LibPQ.jl/src/connections.jl:279
 [3] LibPQ.Connection(str::String)
   @ LibPQ ~/repos/invenia/LibPQ.jl/src/connections.jl:265
 [4] top-level scope
   @ REPL[4]:1

julia> conn = LibPQ.Connection("host=localhost dbname=postgres user=postgres password=password123");

julia> println("isopen(conn) = ", isopen(conn))
isopen(conn) = true

julia> result = execute(conn, "SELECT tablename FROM pg_catalog.pg_tables LIMIT 3;");

julia> println("result[1, 1] = ", result[1, 1])
result[1, 1] = pg_statistic

julia> close(result)

julia> execute(conn, "SELCET 1;")
┌ Error: SyntaxError: ERROR:  syntax error at or near "SELCET"
│ LINE 1: SELCET 1;
│         ^
└ @ LibPQ ~/repos/invenia/LibPQ.jl/src/results.jl:236
ERROR: SyntaxError: ERROR:  syntax error at or near "SELCET"
LINE 1: SELCET 1;
        ^
Stacktrace:
 [1] handle_result(jl_result::LibPQ.Result{false}; throw_error::Bool)
   @ LibPQ ~/repos/invenia/LibPQ.jl/src/results.jl:236
 [2] handle_result
   @ ~/repos/invenia/LibPQ.jl/src/results.jl:228 [inlined]
 [3] _multi_execute(jl_conn::LibPQ.Connection, query::String; throw_error::Bool, kwargs::@Kwargs{})
   @ LibPQ ~/repos/invenia/LibPQ.jl/src/results.jl:304
 [4] _multi_execute
   @ ~/repos/invenia/LibPQ.jl/src/results.jl:297 [inlined]
 [5] #execute#49
   @ ~/repos/invenia/LibPQ.jl/src/results.jl:293 [inlined]
 [6] execute(conn::LibPQ.Connection, query::String)
   @ LibPQ ~/repos/invenia/LibPQ.jl/src/results.jl:289
 [7] top-level scope
   @ REPL[10]:1

julia> execute(conn, "SELCET 1;"; throw_error=false);
┌ Warning: SyntaxError: ERROR:  syntax error at or near "SELCET"
│ LINE 1: SELCET 1;
│         ^
└ @ LibPQ ~/repos/invenia/LibPQ.jl/src/results.jl:238

julia> close(conn)

rofinn added 4 commits July 26, 2026 21:49
1. Added Logging as a dependency
2. Updated connections.jl to use the Logging macros instead of Memento
   functions
3. Updated the corresponding tests, so everything remains green

NOTES:
- @error just takes a string, so we need to (1) use sprint and (2)
  explicitly throw to maintain behaviour.
- Logging doesn't have a @test_nolog, so the test utility function
  `test_nolog_on_windows` is a bit uglier.
1. Mostly the same changes and ugliness as previous commit.
2. For copy.jl we're using @logmsg with an explicit level to handle the
   Warn vs Error condition
3. Since we're directly using Logging.Error, Logging.Warn and @logmsg
   we've made Logging a direct dependency.
One awkward part of this is that LibPQ logs will now show up in the docs
output and we can't easily bypass that. Previously we were able to just
silence LibPQ logger messages because they were completely independent
of the Logging logger.
I tried setting the `global_logger` using
`LoggingExtras.EarlyFilteredLogger`, but that doesn't work because
Documenter uses IOCapture which internally uses
`with_logger(ConsoleLogger(...)` and overrides our global setting.

-
  https://github.com/JuliaDocs/Documenter.jl/blob/v1.17.0/src/doctests.jl#L278
-
  https://github.com/JuliaDocs/IOCapture.jl/blob/v1.0.0/src/IOCapture.jl#L130

Thankfully, this only comes up in 1 doctest, so I've just added a
`with_logger` to the one doctest and included a comment.
@rofinn rofinn mentioned this pull request Jul 27, 2026
3 tasks
@rofinn
rofinn marked this pull request as draft July 27, 2026 17:26
@rofinn rofinn changed the title [WIP] Memento -> Logging Memento -> Logging Jul 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant