Skip to content

Commit 5a81dd7

Browse files
authored
Improve error messages (swift-server#97)
1 parent 4cd8a49 commit 5a81dd7

File tree

3 files changed

+53
-3
lines changed

3 files changed

+53
-3
lines changed

Sources/RediStack/RedisConnection.swift

+3-3
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ extension RedisConnection {
265265

266266
guard self.isConnected else {
267267
let error = RedisClientError.connectionClosed
268-
logger.warning("\(error.localizedDescription)")
268+
logger.warning("\(error.loggableDescription)")
269269
return self.channel.eventLoop.makeFailedFuture(error)
270270
}
271271
logger.trace("received command request")
@@ -293,7 +293,7 @@ extension RedisConnection {
293293
switch result {
294294
case let .failure(error):
295295
logger.error("command failed", metadata: [
296-
RedisLogging.MetadataKeys.error: "\(error.localizedDescription)"
296+
RedisLogging.MetadataKeys.error: "\(error.loggableDescription)"
297297
])
298298

299299
case let .success(value):
@@ -448,7 +448,7 @@ extension RedisConnection {
448448
logger.debug(
449449
"failed to add subscriptions that triggered pubsub mode. removing handler",
450450
metadata: [
451-
RedisLogging.MetadataKeys.error: "\(error.localizedDescription)"
451+
RedisLogging.MetadataKeys.error: "\(error.loggableDescription)"
452452
]
453453
)
454454
// if there was an error, no subscriptions were made

Sources/RediStack/RedisError.swift

+13
Original file line numberDiff line numberDiff line change
@@ -55,3 +55,16 @@ extension RedisError: RESPValueConvertible {
5555
return .error(self)
5656
}
5757
}
58+
59+
extension Error {
60+
/// Provides a description of the error which is suitable for logging
61+
/// This uses localizedDescription if it is implemented, otherwise falls back to default string representation
62+
/// This avoids hiding details for errors coming from other libraries (e.g. from swift-nio) which don't
63+
/// conform to LocalizedError
64+
var loggableDescription: String {
65+
if self is LocalizedError {
66+
return self.localizedDescription
67+
}
68+
return "\(self)"
69+
}
70+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the RediStack open source project
4+
//
5+
// Copyright (c) YEARS RediStack project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of RediStack project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
@testable import RediStack
16+
import XCTest
17+
18+
final class RedisErrorTests: XCTestCase {
19+
func testLoggableDescriptionLocalized() {
20+
let error = RedisError(reason: "test")
21+
XCTAssertEqual(error.loggableDescription, "(Redis) test")
22+
}
23+
24+
func testLoggableDescriptionNotLocalized() {
25+
struct MyError: Error, CustomStringConvertible {
26+
var field: String
27+
var description: String {
28+
"description of \(self.field)"
29+
}
30+
}
31+
let error = MyError(field: "test")
32+
XCTAssertEqual(error.loggableDescription, "description of test")
33+
// Trying to take a localizedDescription would give a less useful message like
34+
// "The operation couldn’t be completed. (RediStackTests.RedisErrorTests.(unknown context at $10aa9f334).(unknown context at $10aa9f340).MyError error 1.)"
35+
XCTAssertTrue(error.localizedDescription.contains("unknown context"))
36+
}
37+
}

0 commit comments

Comments
 (0)