Skip to content

feat(slog): add support for structured and leveled logger#1756

Merged
kavirajk merged 7 commits intomainfrom
kavirajk/level-logger
Jan 23, 2026
Merged

feat(slog): add support for structured and leveled logger#1756
kavirajk merged 7 commits intomainfrom
kavirajk/level-logger

Conversation

@kavirajk
Copy link
Copy Markdown
Contributor

@kavirajk kavirajk commented Jan 21, 2026

Summary

  1. Uses standard lib's log/slog as a main logger.
  2. Deprecates the old way of logging via Debug flag and DebugF
  3. Provide adapter for legacy way of logging with no-op logging
  4. Backward compatible with Debug and DebugF apporach of logging

closes: #1698

Notes (for the reviewers):

  1. There are only few significant changes that deserves full review (which I marked as comments)
  2. Most of the file changes are updating the caller of log lines.

FAQ:

  1. Why deprecate Debug and DebugF - These are unstructured log lines, no labels, no filterable, no much pattern.
  2. Why update all the call-sites? - With proper levels and structured labels improve the logging UX
  3. Why use slog? why not new Logger interface - slog is from standard library, and has all the helpers and log levels already.
  4. Is updating the existing Debug logs breaking changes?. No. it's debug logs.

Checklist

Delete items not relevant to your PR:

1. Uses standard lib's log/slog as a main logger.
2. Deprecates the old way of logging via Debug flag and DebugF
3. Provide adapter for legacy way of logging with no-op logging
4. Backward compatible with Debug and DebugF apporach of logging

Signed-off-by: Kaviraj <[email protected]>
@kavirajk kavirajk requested a review from chernser as a code owner January 21, 2026 15:49
@kavirajk kavirajk marked this pull request as draft January 21, 2026 15:49
1. No more un-structured `debug` calls
2. Examples on how to use proper structured logging on both transport

Signed-off-by: Kaviraj <[email protected]>
@@ -0,0 +1,125 @@
package clickhouse
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Main logger implementation.

isReleased() bool
setReleased(released bool)
debugf(format string, v ...any)
getLogger() *slog.Logger
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is needed to provide connection contexts to connection polling. Without this, the connection pooling doesn't know what's the connection-id, remote-addr, etc. and logs will be very generic like "acquired connection", "releasing connection"

//
// For backward compatibility, if Debug=true and Debugf is set, those will be used
// instead of Logger.
Logger *slog.Logger
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the main UX from the user POV. That accepts logger as separate dependency.

// 1. If Debug=true and Debugf is set, use legacy Debugf (backward compatibility)
// 2. If Logger is set, use the provided logger
// 3. Otherwise, use a noop logger (no logging)
func (o *Options) logger() *slog.Logger {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Provides "sane" default values for logger. Also take into the legacy Debug flag way of doing logging.

@kavirajk kavirajk marked this pull request as ready for review January 22, 2026 17:04
clickhouse.go Outdated
return nil, err
}
conn.debugf("[query] \"%s\"", query)
conn.getLogger().Info("executing query", slog.String("sql", query))
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • there is a high security risk when logging SQL statements - they may contain sensitive information (SSN, credit card number etc). Usually this is done on debug/trace level only and by dedicated logger (ex.: clickhouse.client.sql_logger)
  • Logging with info level is too annoying in most case and can be quite expensive for customers. SQL in this case can be quite large so it will be a problem. Previously it was on debug level. I'd put it on trace level because client seems do very little with SQL itself .

There is more useful bit of information that can be logged- queryID

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree. logging query shouldn't be info. I'm putting back to Debug (trace level is not a norm in Go).

because client seems do very little with SQL itself .
There is more useful bit of information that can be logged- queryID

Sometimes I would like to see the full SQL (in Debug of course) with all the prepare statement get expanded and format applied. Just the actual query sent to the server. Also unfortunately we don't have access to queryID at this level.

}
if err := s.batch.Append(values...); err != nil {
s.debugf("[batch][exec] append error: %v", err)
s.logger.Error("batch append error", slog.Any("error", err))
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it really required to log error on this level?
User should be able to log it if needed - anyway error is returned as result.
I'd remove logging here completely or leave it on debug level.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think removing is better. 👍 thanks

@chernser
Copy link
Copy Markdown

@kavirajk

I suggest keep log level as before (ex.: previously errors were logged on debug level)
Please make logging of query on debug level to avoid security issues (besides it was debug before)

@kavirajk kavirajk requested a review from chernser January 23, 2026 13:38
@kavirajk kavirajk merged commit 308e8fa into main Jan 23, 2026
13 checks passed
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.

Logging: Support logging levels

2 participants