Skip to content

Commit 2e7510a

Browse files
committed
[PlaygroundLogger] Updated everything to throw errors instead of calling through to loggingError.
This means that logging shouldn't cause crashes, except in truly exceptional cases in the logger. These errors are not quite propagated yet; that will come in a follow-up commit.
1 parent 610af1b commit 2e7510a

18 files changed

+125
-89
lines changed

PlaygroundLogger/PlaygroundLogger/CustomLoggable/CoreImage/CIColor+CustomOpaqueLoggable.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import CoreImage
1515
extension CIColor: CustomOpaqueLoggable {
1616
func opaqueRepresentation() throws -> LogEntry.OpaqueRepresentation {
1717
guard let color = CGColor(colorSpace: self.colorSpace, components: self.components) else {
18-
loggingError("Unable to convert CIColor to CGColor")
18+
throw LoggingError.failedToGenerateOpaqueRepresentation(reason: "Unable to convert this CIColor to a CGColor")
1919
}
2020

2121
return color

PlaygroundLogger/PlaygroundLogger/CustomLoggable/SpriteKit/SpriteKitOpaqueLoggable.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ import SpriteKit
2121
fileprivate protocol SpriteKitOpaqueLoggable: class, OpaqueImageRepresentable, CustomOpaqueLoggable {}
2222

2323
extension SpriteKitOpaqueLoggable {
24-
func encodeImage(into encoder: LogEncoder, withFormat format: LogEncoder.Format) {
24+
func encodeImage(into encoder: LogEncoder, withFormat format: LogEncoder.Format) throws {
2525
guard let copyImageDataMethod = (self as AnyObject)._copyImageData, let imageData = copyImageDataMethod() else {
26-
loggingError("SpriteKit did not return any image data")
26+
throw LoggingError.encodingFailure(reason: "Unable to get image data for \(type(of: self))")
2727
}
2828

2929
encoder.encode(number: UInt64(imageData.count))

PlaygroundLogger/PlaygroundLogger/LegacySupport/LegacyEntrypoints.swift

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,26 +37,37 @@ fileprivate func legacySendDataStub(_: NSData) -> Void {
3737
@_silgen_name("playground_log_hidden")
3838
public func legacyLog<T>(instance: T, name: String, id: Int, startLine: Int, endLine: Int, startColumn: Int, endColumn: Int) -> AnyObject {
3939
let packet = LogPacket(describingResult: instance, named: name, withPolicy: .default, startLine: startLine, endLine: endLine, startColumn: startColumn, endColumn: endColumn)
40-
41-
let data = packet.encode()
40+
41+
let data: Data
42+
do {
43+
data = try packet.encode()
44+
}
45+
catch {
46+
let errorPacket = LogPacket(errorWithReason: "Error occurred while encoding log packet", startLine: startLine, endLine: endLine, startColumn: startColumn, endColumn: endColumn, threadID: packet.threadID)
47+
48+
// Encoding an error packet should not fail under any circumstances.
49+
data = try! errorPacket.encode()
50+
}
4251

4352
return data as NSData
4453
}
4554

4655
@_silgen_name ("playground_log_scope_entry")
4756
public func legacyLogScopeEntry(startLine: Int, endLine: Int, startColumn: Int, endColumn: Int) -> AnyObject {
4857
let packet = LogPacket(scopeEntryWithStartLine: startLine, endLine: endLine, startColumn: startColumn, endColumn: endColumn)
49-
50-
let data = packet.encode()
58+
59+
// Encoding a scope entry packet should not fail under any circumstances.
60+
let data = try! packet.encode()
5161

5262
return data as NSData
5363
}
5464

5565
@_silgen_name ("playground_log_scope_exit")
5666
public func legacyLogScopeExit(startLine: Int, endLine: Int, startColumn: Int, endColumn: Int) -> AnyObject {
5767
let packet = LogPacket(scopeExitWithStartLine: startLine, endLine: endLine, startColumn: startColumn, endColumn: endColumn)
58-
59-
let data = packet.encode()
68+
69+
// Encoding a scope exit packet should not fail under any circumstances.
70+
let data = try! packet.encode()
6071

6172
return data as NSData
6273
}
@@ -69,7 +80,16 @@ func legacyLogPostPrint(startLine: Int, endLine: Int, startColumn: Int, endColum
6980

7081
let packet = LogPacket(printedString: printedString, startLine: startLine, endLine: endLine, startColumn: startColumn, endColumn: endColumn)
7182

72-
let data = packet.encode()
83+
let data: Data
84+
do {
85+
data = try packet.encode()
86+
}
87+
catch {
88+
let errorPacket = LogPacket(errorWithReason: "Error occurred while encoding log packet", startLine: startLine, endLine: endLine, startColumn: startColumn, endColumn: endColumn, threadID: packet.threadID)
89+
90+
// Encoding an error packet should not fail under any circumstances.
91+
data = try! errorPacket.encode()
92+
}
7393

7494
return data as NSData
7595
}

PlaygroundLogger/PlaygroundLogger/LegacySupport/PlaygroundQuickLook+OpaqueRepresentationSupport.swift

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -33,54 +33,54 @@ extension PlaygroundQuickLook {
3333
return float
3434
case let .double(double):
3535
return double
36-
case let .image(image):
36+
case let .image(imageObject):
3737
#if os(macOS)
38-
guard let image = image as? NSImage else {
39-
loggingError("Must be an NSImage")
38+
guard let image = imageObject as? NSImage else {
39+
throw LoggingError.failedToGenerateOpaqueRepresentation(reason: "Image is not an NSImage; it is '\(type(of: imageObject))' instead")
4040
}
4141

4242
return ImageOpaqueRepresentation(kind: .image, backedBy: image)
4343
#elseif os(iOS) || os(tvOS)
44-
guard let image = image as? UIImage else {
45-
loggingError("Must be an IOImage")
44+
guard let image = imageObject as? UIImage else {
45+
throw LoggingError.failedToGenerateOpaqueRepresentation(reason: "Image is not a UIImage; it is '\(type(of: imageObject))' instead")
4646
}
4747

4848
return ImageOpaqueRepresentation(kind: .image, backedBy: image)
4949

5050
#endif
5151
case .sound:
52-
loggingError("Sounds not supported")
53-
case let .color(color):
52+
throw LoggingError.failedToGenerateOpaqueRepresentation(reason: "Sounds are not supported")
53+
case let .color(colorObject):
5454
#if os(macOS)
55-
guard let color = color as? NSColor else {
56-
loggingError("Must be an NSColor")
55+
guard let color = colorObject as? NSColor else {
56+
throw LoggingError.failedToGenerateOpaqueRepresentation(reason: "Color is not an NSColor; it is '\(type(of: colorObject))' instead")
5757
}
5858

5959
return color.cgColor
6060
#elseif os(iOS) || os(tvOS)
61-
guard let color = color as? UIColor else {
62-
loggingError("Must be a UIColor")
61+
guard let color = colorObject as? UIColor else {
62+
throw LoggingError.failedToGenerateOpaqueRepresentation(reason: "Color is not a UIColor; it is '\(type(of: colorObject))' instead")
6363
}
6464

6565
return color.cgColor
6666
#endif
67-
case let .bezierPath(bezierPath):
67+
case let .bezierPath(bezierPathObject):
6868
#if os(macOS)
69-
guard let bezierPath = bezierPath as? NSBezierPath else {
70-
loggingError("Must be an NSBezierPath")
69+
guard let bezierPath = bezierPathObject as? NSBezierPath else {
70+
throw LoggingError.failedToGenerateOpaqueRepresentation(reason: "Bezier path is not an NSBezierPath; it is '\(type(of: bezierPathObject))' instead")
7171
}
7272

7373
return bezierPath
7474
#elseif os(iOS) || os(tvOS)
75-
guard let bezierPath = bezierPath as? UIBezierPath else {
76-
loggingError("Must be a UIBezierPath")
75+
guard let bezierPath = bezierPathObject as? UIBezierPath else {
76+
throw LoggingError.failedToGenerateOpaqueRepresentation(reason: "Bezier path is not a UIBezierPath; it is '\(type(of: bezierPathObject))' instead")
7777
}
7878

7979
return bezierPath
8080
#endif
81-
case let .attributedString(attributedString):
82-
guard let attributedString = attributedString as? NSAttributedString else {
83-
loggingError("Must be an NSAttributedString")
81+
case let .attributedString(attributedStringObject):
82+
guard let attributedString = attributedStringObject as? NSAttributedString else {
83+
throw LoggingError.failedToGenerateOpaqueRepresentation(reason: "Attributed string is not an NSAttributedString; it is '\(type(of: attributedStringObject))' instead")
8484
}
8585

8686
return attributedString
@@ -103,7 +103,7 @@ extension PlaygroundQuickLook {
103103
return ImageOpaqueRepresentation(kind: .view, backedBy: image)
104104
}
105105
else {
106-
loggingError("Must be an NSView or NSImage")
106+
throw LoggingError.failedToGenerateOpaqueRepresentation(reason: "View is not an NSView or NSImage; is is '\(type(of: viewOrImage))' instead")
107107
}
108108
#elseif os(iOS) || os(tvOS)
109109
if let view = viewOrImage as? UIView {
@@ -113,27 +113,27 @@ extension PlaygroundQuickLook {
113113
return ImageOpaqueRepresentation(kind: .view, backedBy: image)
114114
}
115115
else {
116-
loggingError("Must be a UIView or UIImage")
116+
throw LoggingError.failedToGenerateOpaqueRepresentation(reason: "View is not a UIView or UIImage; is is '\(type(of: viewOrImage))' instead")
117117
}
118118
#endif
119-
case let .sprite(image):
119+
case let .sprite(imageObject):
120120
// TODO: figure out if this is even a little bit right. (The previous implementation just logged a string for sprites?)
121121
#if os(macOS)
122-
guard let image = image as? NSImage else {
123-
loggingError("Must be an NSImage")
122+
guard let image = imageObject as? NSImage else {
123+
throw LoggingError.failedToGenerateOpaqueRepresentation(reason: "Sprite is not an NSImage; it is '\(type(of: imageObject))' instead")
124124
}
125125

126126
return ImageOpaqueRepresentation(kind: .sprite, backedBy: image)
127127
#elseif os(iOS) || os(tvOS)
128-
guard let image = image as? UIImage else {
129-
loggingError("Must be a UIImage")
128+
guard let image = imageObject as? UIImage else {
129+
throw LoggingError.failedToGenerateOpaqueRepresentation(reason: "Sprite is not a UIImage; it is '\(type(of: imageObject))' instead")
130130
}
131131

132132
return ImageOpaqueRepresentation(kind: .sprite, backedBy: image)
133133
#endif
134134
case let .url(urlString):
135135
guard let url = URL(string: urlString) else {
136-
loggingError("Must be a valid URL string!")
136+
throw LoggingError.failedToGenerateOpaqueRepresentation(reason: "String is not a valid URL string")
137137
}
138138

139139
return url

PlaygroundLogger/PlaygroundLogger/LogEntry+Encoding.swift

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ extension LogEntry {
6666
}
6767
}
6868

69-
func encode(with encoder: LogEncoder, format: LogEncoder.Format) {
69+
func encode(with encoder: LogEncoder, format: LogEncoder.Format) throws {
7070
// Start by encoding the name of the log entry.
7171
encoder.encode(string: name)
7272

@@ -76,9 +76,9 @@ extension LogEntry {
7676
// Finally, encode the entry-type-specific information.
7777
switch self {
7878
case let.structured(_, typeName, summary, totalChildrenCount, children, _):
79-
LogEntry.encode(structuredWithTypeName: typeName, summary: summary, totalChildrenCount: totalChildrenCount, children: children, into: encoder, usingFormat: format)
79+
try LogEntry.encode(structuredWithTypeName: typeName, summary: summary, totalChildrenCount: totalChildrenCount, children: children, into: encoder, usingFormat: format)
8080
case let .opaque(_, typeName, summary, preferBriefSummary, representation):
81-
LogEntry.encode(opaqueWithTypeName: typeName, summary: summary, preferBriefSummary: preferBriefSummary, representation: representation, into: encoder, usingFormat: format)
81+
try LogEntry.encode(opaqueWithTypeName: typeName, summary: summary, preferBriefSummary: preferBriefSummary, representation: representation, into: encoder, usingFormat: format)
8282
case .gap, .scopeEntry, .scopeExit:
8383
// Gap, scope entry, and scope exit entries contain no additional data beyond what's common to all log entry types.
8484
break
@@ -87,7 +87,7 @@ extension LogEntry {
8787
}
8888
}
8989

90-
private static func encode(structuredWithTypeName typeName: String, summary: String, totalChildrenCount: Int, children: [LogEntry], into encoder: LogEncoder, usingFormat format: LogEncoder.Format) {
90+
private static func encode(structuredWithTypeName typeName: String, summary: String, totalChildrenCount: Int, children: [LogEntry], into encoder: LogEncoder, usingFormat format: LogEncoder.Format) throws {
9191
// Structured entries contain the following type-specific information:
9292
// - Type name, encoded as a string
9393
// - Summary, encoded as a string
@@ -103,10 +103,10 @@ extension LogEntry {
103103
guard totalChildrenCount > 0 else { return }
104104

105105
encoder.encode(number: UInt64(children.count))
106-
children.forEach { $0.encode(with: encoder, format: format) }
106+
try children.forEach { try $0.encode(with: encoder, format: format) }
107107
}
108108

109-
private static func encode(opaqueWithTypeName typeName: String, summary: String, preferBriefSummary: Bool, representation: LogEntry.OpaqueRepresentation, into encoder: LogEncoder, usingFormat format: LogEncoder.Format) {
109+
private static func encode(opaqueWithTypeName typeName: String, summary: String, preferBriefSummary: Bool, representation: LogEntry.OpaqueRepresentation, into encoder: LogEncoder, usingFormat format: LogEncoder.Format) throws {
110110
// Opaque entries contain the following type-specific information:
111111
// - Prefers brief summary, encoded as a boolean
112112
// - Type name, encoded as a string
@@ -119,7 +119,8 @@ extension LogEntry {
119119
encoder.encode(boolean: preferBriefSummary)
120120
encoder.encode(string: typeName)
121121
encoder.encode(string: summary)
122-
representation.encode(into: encoder, usingFormat: format)
122+
123+
try representation.encode(into: encoder, usingFormat: format)
123124
}
124125

125126
private static func encode(errorWithReason reason: String, into encoder: LogEncoder) {

PlaygroundLogger/PlaygroundLogger/LogEntry.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ enum LogEntry {
3333
}
3434

3535
protocol OpaqueLogEntryRepresentation {
36-
func encode(into encoder: LogEncoder, usingFormat format: LogEncoder.Format)
36+
func encode(into encoder: LogEncoder, usingFormat format: LogEncoder.Format) throws
3737
}
3838

3939
private let emptyName = ""

PlaygroundLogger/PlaygroundLogger/LogPacket+Encoding.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
import Foundation
1414

1515
extension LogPacket {
16-
func encode(inFormat format: LogEncoder.Format = .current) -> Data {
16+
func encode(inFormat format: LogEncoder.Format = .current) throws -> Data {
1717
let encoder = LogEncoder()
1818

1919
// Encode the format version.
@@ -31,7 +31,7 @@ extension LogPacket {
3131
encoder.encode(string: threadID)
3232

3333
// Encode our top-level log entry. (This will add any child entries automatically.)
34-
logEntry.encode(with: encoder, format: format)
34+
try logEntry.encode(with: encoder, format: format)
3535

3636
return encoder.encodedData
3737
}

PlaygroundLogger/PlaygroundLogger/LoggerEntrypoints.swift

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,16 @@ func logResult(_ result: Any,
2121
endColumn: Int) {
2222
let packet = LogPacket(describingResult: result, named: name, withPolicy: .default, startLine: startLine, endLine: endLine, startColumn: startColumn, endColumn: endColumn)
2323

24-
let data = packet.encode()
24+
let data: Data
25+
do {
26+
data = try packet.encode()
27+
}
28+
catch {
29+
let errorPacket = LogPacket(errorWithReason: "Error occurred while encoding log packet", startLine: startLine, endLine: endLine, startColumn: startColumn, endColumn: endColumn, threadID: packet.threadID)
30+
31+
// Encoding an error packet should not fail under any circumstances.
32+
data = try! errorPacket.encode()
33+
}
2534

2635
sendData(data as NSData)
2736
}
@@ -31,8 +40,9 @@ func logScopeEntry(startLine: Int,
3140
startColumn: Int,
3241
endColumn: Int) {
3342
let packet = LogPacket(scopeEntryWithStartLine: startLine, endLine: endLine, startColumn: startColumn, endColumn: endColumn)
34-
35-
let data = packet.encode()
43+
44+
// Encoding a scope entry packet should not fail under any circumstances.
45+
let data = try! packet.encode()
3646

3747
sendData(data as NSData)
3848
}
@@ -42,8 +52,9 @@ func logScopeExit(startLine: Int,
4252
startColumn: Int,
4353
endColumn: Int) {
4454
let packet = LogPacket(scopeExitWithStartLine: startLine, endLine: endLine, startColumn: startColumn, endColumn: endColumn)
45-
46-
let data = packet.encode()
55+
56+
// Encoding a scope exit packet should not fail under any circumstances.
57+
let data = try! packet.encode()
4758

4859
sendData(data as NSData)
4960
}
@@ -66,7 +77,16 @@ func logPostPrint(startLine: Int,
6677

6778
let packet = LogPacket(printedString: printedString, startLine: startLine, endLine: endLine, startColumn: startColumn, endColumn: endColumn)
6879

69-
let data = packet.encode()
80+
let data: Data
81+
do {
82+
data = try packet.encode()
83+
}
84+
catch {
85+
let errorPacket = LogPacket(errorWithReason: "Error occurred while encoding log packet", startLine: startLine, endLine: endLine, startColumn: startColumn, endColumn: endColumn, threadID: packet.threadID)
86+
87+
// Encoding an error packet should not fail under any circumstances.
88+
data = try! errorPacket.encode()
89+
}
7090

7191
sendData(data as NSData)
7292
}

PlaygroundLogger/PlaygroundLogger/OpaqueRepresentations/AppKit/NSBitmapImageRep+OpaqueImageRepresentable.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@
1414
import AppKit
1515

1616
extension NSBitmapImageRep: OpaqueImageRepresentable {
17-
func encodeImage(into encoder: LogEncoder, withFormat format: LogEncoder.Format) {
17+
func encodeImage(into encoder: LogEncoder, withFormat format: LogEncoder.Format) throws {
1818
guard let pngData = self.representation(using: .png, properties: [:]) else {
19-
loggingError("Failed to generate PNG data")
19+
throw LoggingError.encodingFailure(reason: "Failed to generate PNG data for the bitmap representation")
2020
}
2121

2222
encoder.encode(number: UInt64(pngData.count))

PlaygroundLogger/PlaygroundLogger/OpaqueRepresentations/AppKit/NSImage+OpaqueImageRepresentable.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,12 @@
3232
}
3333
}
3434

35-
func encodeImage(into encoder: LogEncoder, withFormat format: LogEncoder.Format) {
35+
func encodeImage(into encoder: LogEncoder, withFormat format: LogEncoder.Format) throws {
3636
guard let bitmapRep = self.bestBitmapRepresentation else {
37-
loggingError("Failed to convert image to a bitmap representation")
37+
throw LoggingError.encodingFailure(reason: "Failed to get a bitmap representation of this NSImage")
3838
}
3939

40-
bitmapRep.encodeImage(into: encoder, withFormat: format)
40+
try bitmapRep.encodeImage(into: encoder, withFormat: format)
4141
}
4242
}
4343
#endif

0 commit comments

Comments
 (0)