Skip to content

Unify LoggerFragmentBuilder and LoggerSpacedFragmentBuilder#231

Merged
0xTim merged 2 commits intovapor:consolekit-5from
fpseverino:improve-builders
Apr 7, 2026
Merged

Unify LoggerFragmentBuilder and LoggerSpacedFragmentBuilder#231
0xTim merged 2 commits intovapor:consolekit-5from
fpseverino:improve-builders

Conversation

@fpseverino
Copy link
Copy Markdown
Member

Merge LoggerFragmentBuilder and LoggerSpacedFragmentBuilder using a Integer Generic Parameter to specify the number of spaces to add between fragments

@fpseverino fpseverino requested review from 0xTim and gwynne as code owners March 12, 2026 17:26
}

/// A fragment that wraps another fragment, automatically separating its components with spaces.
@available(macOS 26.0, iOS 26.0, watchOS 26.0, tvOS 26.0, macCatalyst 26.0, visionOS 26.0, *)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

What in this requires adding availability annotations? And doesn't this affect anyone using a logger fragment?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think it's the use of integer generics that requires the annotation. Which makes it problematic IMO; I think Tahoe is too strict a requirement as of yet.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I mean it's fine if it's scoped to just these APIs and the rest is fine which it looks like, but I'm not 100%.

Also Vapor 5 will be 26+ only given the Span usage so I'm happy to just bump that if necessary, but given the logger is used for more than Vapor I'd like to try and make it as permissive as possible

Copy link
Copy Markdown
Member Author

@fpseverino fpseverino Apr 7, 2026

Choose a reason for hiding this comment

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

Yes, it's for the integer generics. Tahoe would be required only for the LoggerFragment DSL though, the old API would still be available on older macOS versions.

Also, I guess macOS 27 would already be out when we release the definitive v5 of ConsoleKit.

Copy link
Copy Markdown
Member

@0xTim 0xTim left a comment

Choose a reason for hiding this comment

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

Ok cool, fine by me

@0xTim 0xTim merged commit 8313b62 into vapor:consolekit-5 Apr 7, 2026
18 of 20 checks passed
@gwynne
Copy link
Copy Markdown
Member

gwynne commented Apr 7, 2026

To be honest, I'm a bit soured on the entire concept of "log fragments" and builders for them at this point. I've found that this (with a couple of additional supporting bits) works just fine for my needs:

extension Logger {
  /// A container for a formatter closure which accepts as input all parameters related to a log message and returns a
  /// simple string containing the final raw output. Modeled after `Logger.MetadataProvider`.
  public struct MessageFormatter: Sendable {
    /// The type of a closure which accepts all parameters related to a log message and returns a formatted raw string.
    ///
    /// See ``format(timestamp:event:)`` for details on the semantics of the closure's parameters.
    public typealias Formatter = @Sendable (_ timestamp: Date, _ event: LogEvent) -> String

    private let formatter: Formatter

    /// Create a formatter with a formatter closure.
    public init(_ formatter: @escaping Formatter) { self.formatter = formatter }

    /// Apply the formatter to the given inputs and return its result.
    ///
    /// - Parameters:
    ///   - timestamp: The timestamp of the log message.
    ///   - event: The `LogEvent` containing the various data representing the log message. The `metadata` field of the event will
    ///     contain the result of merging the logger's configured metadata, the metadata from the logger's configured metadata provider,
    ///     and the metadata specific to the specific log message,in that order.
    /// - Returns: The formatted log message.
    public func format(timestamp: Date, event: LogEvent) -> String { self.formatter(timestamp, event) }
  }
}

/// A log handler which automatically applies a `Logger.MessageFormatter` to each log message it receives.
///
/// A per-message timestamp is provided for each log message, and the logger label is provided as a protocol requirement.
public protocol MessageFormattingLogHandler: LogHandler {
  /// The label applied to the log handler at its creation.
  var label: String { get }

  /// The message formatter to be applied to each log message.
  var messageFormatter: Logger.MessageFormatter { get set }

  /// Log a preformatted message having the given parameters.
  ///
  /// Although the log event has already been used in formatting the message, it is also provided here for the handler's usage.
  /// The label is not passed to this method because it is already available via the protocol.
  ///
  /// - Parameters:
  ///   - timestamp: The timestamp of the log message (always `Date.now` at the point that the message was logged).
  ///   - event: The `LogEvent` containing the various data representing the log message. The `metadata` field of the event will
  ///     contain the result of merging the logger's configured metadata, the metadata from the logger's configured metadata provider,
  ///     and the metadata specific to the specific log message,in that order.
  func log(timestamp: Date, event: LogEvent)
}

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.

3 participants