Open Integralist opened 10 months ago
My gut reaction is that would require a new connection type.
In the longer term a v2 package could look to use functional options to significantly reduce API surface area and simplify the creation of connection, with and without timeout, loggers etc.
I'd be interested to hear your thoughts on what the goals of structure logging for the package might be?
@stevenh do the internals depend on a concrete log.Logger
or an interface?
Would you consider a backwards-compatible PR that adds the ability to create a connection that accepts something conforming to an interface, e.g. redis.Logger
or something?
Quick look indicates it only uses https://pkg.go.dev/log#Logger.Output, but the implementation in its current form wouldn't be particularly useful structure logging from what I can see as it uses buffer to create a single string output.
We couldn't break the existing API so would need new constructor to change the way it's passed in.
Overall I'm not sure changing the existing one would achieve what you're looking for hence my question about what the goal you're trying to achieve is?
Yeah, I agree, a new constructor would be the better way to go here.
I presume the addition of a new constructor would still require threading changes through the call stack for redigo to support either a log.Logger
and slog.Logger
.
As far as the question...
what the goals of structure logging for the package might be?
Our application currently uses log.Logger
and we're looking to upgrade to the new slog package so we can benefit from more structured logging, so having our log output be consistent across redigo would be nice.
what the goals of structure logging for the package might be?
Our application currently uses
log.Logger
and we're looking to upgrade to the new slog package so we can benefit from more structured logging, so having our log output be consistent across redigo would be nice.
But I'm guessing this would also include the use of structure, so a direct port the current logger wouldn't provide the full benefit even if it would enable you to use the same logger, I'm thinking performance and actual structure so things could be filtered base on action etc?
I think all we need is log/slog.NewLogLogger()
and to pass that to the existing constructor.
If that's the case no changes needed?
I think I was thinking more scope, to add structure and improve performance.
So yeah at the moment I'm actually just getting by with slog.NewLogLogger()
redis.NewLoggingConn(c, slog.NewLogLogger(std.Handler(), slog.LevelInfo), "redis")
This is fine to unblock me, but I would imagine actual support for slog
in redigo would require some changes which will depend on how it's implemented.
So we know from prior discussion that a new constructor that accepts a *slog.Logger
type would be preferred over a new major release that changes the API to accept an interface.
But then the underlying loggingConn
needs to have the logger stored off. So do you change the logger
field to use an interface type and you build an abstraction over the top of it so that each logger call site will call down to its relevant instance (e.g. *log.Logger
vs *slog.Logger
).
Or do you have a new field added, like slogger *slog.Logger
, and again, each call site where a log record is made the code has to check if logger
or slogger
is nil and then whichever isn't nil
will get called.
And on top of that, regardless of the approach (new field vs interface type), redigo needs to structure the data (if dealing with *slog.Logger
).
e.g. go from...
func (c *loggingConn) Close() error {
// ...
c.logger.Output(2, buf.String())
}
...to...
func (c *loggingConn) Close() error {
// ...
c.logger.LogAttrs(context.Background(), slog.LevelInfo, "closing connection",
slog.String("event", "conn_close"),
)
}
Probably not a great example ☝🏻 as I've realised just now how simple the log call actually is 🙂
I imagine the print()
method probably would gain a bit more 'structure'.
But yeah, that was generally what I was thinking in my head.
Without looking in detail I'd be tempted to create a new logging connection that has proper slog support. If that could then be used to provide a compatible constructor for the original even better.
Had poke around in this, and while it would simple to create a new logging connection type with proper slog support, I already have 95% written, I do wonder if this is driven by the current structure, which it makes is hard to enhance current or add new features easily.
How do folks currently use this feature, code snippets would be most appreciated.
I'm wondering if it's time for a v2 that supports a progressive design such as functional options?
Nice! That escalated fast!
👋🏻
I was looking to migrate from
log
tolog/slog
and noticed that https://pkg.go.dev/github.com/gomodule/redigo@v1.8.9/redis#NewLoggingConn is constrained to the former.What is the plan as far as supporting the new structured logging package?
I presume you'd want to modify the various signatures to using an interface rather than a concrete type.
Thanks.