@@ -12,8 +12,6 @@ import Dispatch
12
12
import TSCBasic
13
13
import TSCUtility
14
14
15
- typealias TSCDiagnostic = TSCBasic . Diagnostic
16
-
17
15
// this could become a struct when we remove the "errorsReported" pattern
18
16
19
17
// designed after https://github.com/apple/swift-log
@@ -170,25 +168,7 @@ extension DiagnosticsEmitterProtocol {
170
168
}
171
169
172
170
public func emit( _ error: Error , metadata: ObservabilityMetadata ? = . none) {
173
- var metadata = metadata
174
- // FIXME: this brings in the TSC API still
175
- if let errorProvidingLocation = error as? DiagnosticLocationProviding , let diagnosticLocation = errorProvidingLocation. diagnosticLocation {
176
- metadata = metadata ?? ObservabilityMetadata ( )
177
- metadata? . legacyDiagnosticLocation = . init( diagnosticLocation)
178
- }
179
-
180
- let message : String
181
- // FIXME: this brings in the TSC API still
182
- // FIXME: string interpolation seems brittle
183
- if let diagnosticData = error as? DiagnosticData {
184
- message = " \( diagnosticData) "
185
- } else if let convertible = error as? DiagnosticDataConvertible {
186
- message = " \( convertible. diagnosticData) "
187
- } else {
188
- message = " \( error) "
189
- }
190
-
191
- self . emit ( severity: . error, message: message, metadata: metadata)
171
+ self . emit ( . error( error, metadata: metadata) )
192
172
}
193
173
194
174
public func emit( warning message: String , metadata: ObservabilityMetadata ? = . none) {
@@ -215,6 +195,7 @@ extension DiagnosticsEmitterProtocol {
215
195
self . emit ( debug: message. description, metadata: metadata)
216
196
}
217
197
198
+ /// trap a throwing closure, emitting diagnostics on error and returning the value returned by the closure
218
199
public func trap< T> ( _ closure: ( ) throws -> T ) -> T ? {
219
200
do {
220
201
return try closure ( )
@@ -226,6 +207,21 @@ extension DiagnosticsEmitterProtocol {
226
207
return nil
227
208
}
228
209
}
210
+
211
+ /// trap a throwing closure, emitting diagnostics on error and returning boolean representing success
212
+ @discardableResult
213
+ public func trap( _ closure: ( ) throws -> Void ) -> Bool {
214
+ do {
215
+ try closure ( )
216
+ return true
217
+ } catch Diagnostics . fatalError {
218
+ // FIXME: (diagnostics) deprecate this with Diagnostics.fatalError
219
+ return false
220
+ } catch {
221
+ self . emit ( error)
222
+ return false
223
+ }
224
+ }
229
225
}
230
226
231
227
// TODO: consider using @autoclosure to delay potentially expensive evaluation of data when some diagnostics may be filtered out
@@ -245,7 +241,7 @@ public struct DiagnosticsEmitter: DiagnosticsEmitterProtocol {
245
241
}
246
242
}
247
243
248
- public struct Diagnostic : CustomStringConvertible , Equatable {
244
+ public struct Diagnostic : CustomStringConvertible {
249
245
public let severity : Severity
250
246
public let message : String
251
247
public internal ( set) var metadata : ObservabilityMetadata ?
@@ -268,6 +264,31 @@ public struct Diagnostic: CustomStringConvertible, Equatable {
268
264
Self ( severity: . error, message: message. description, metadata: metadata)
269
265
}
270
266
267
+ public static func error( _ error: Error , metadata: ObservabilityMetadata ? = . none) -> Self {
268
+ var metadata = metadata ?? ObservabilityMetadata ( )
269
+
270
+ if metadata. underlyingError == nil {
271
+ metadata. underlyingError = . init( error)
272
+ }
273
+ // FIXME: this brings in the TSC API still
274
+ if let errorProvidingLocation = error as? DiagnosticLocationProviding , let diagnosticLocation = errorProvidingLocation. diagnosticLocation {
275
+ metadata. legacyDiagnosticLocation = . init( diagnosticLocation)
276
+ }
277
+
278
+ let message : String
279
+ // FIXME: this brings in the TSC API still
280
+ // FIXME: string interpolation seems brittle
281
+ if let diagnosticData = error as? DiagnosticData {
282
+ message = " \( diagnosticData) "
283
+ } else if let convertible = error as? DiagnosticDataConvertible {
284
+ message = " \( convertible. diagnosticData) "
285
+ } else {
286
+ message = " \( error) "
287
+ }
288
+
289
+ return Self ( severity: . error, message: message, metadata: metadata)
290
+ }
291
+
271
292
public static func warning( _ message: String , metadata: ObservabilityMetadata ? = . none) -> Self {
272
293
Self ( severity: . warning, message: message, metadata: metadata)
273
294
}
@@ -348,10 +369,10 @@ public struct Diagnostic: CustomStringConvertible, Equatable {
348
369
// FIXME: we currently requires that Value conforms to CustomStringConvertible which sucks
349
370
// ideally Value would conform to Equatable but that has generic requirement
350
371
// luckily, this is about to change so we can clean this up soon
351
- public struct ObservabilityMetadata : Equatable , CustomDebugStringConvertible {
372
+ public struct ObservabilityMetadata : CustomDebugStringConvertible {
352
373
public typealias Key = ObservabilityMetadataKey
353
374
354
- private var _storage = [ AnyKey: CustomStringConvertible ] ( )
375
+ private var _storage = [ AnyKey: Any ] ( )
355
376
356
377
public init ( ) { }
357
378
@@ -382,7 +403,7 @@ public struct ObservabilityMetadata: Equatable, CustomDebugStringConvertible {
382
403
///
383
404
/// - Parameter body: The closure to be invoked for each item stored in this `ObservabilityMetadata`,
384
405
/// passing the type-erased key and the associated value.
385
- public func forEach( _ body: ( AnyKey , CustomStringConvertible ) throws -> Void ) rethrows {
406
+ public func forEach( _ body: ( AnyKey , Any ) throws -> Void ) rethrows {
386
407
try self . _storage. forEach { key, value in
387
408
try body ( key, value)
388
409
}
@@ -402,14 +423,15 @@ public struct ObservabilityMetadata: Equatable, CustomDebugStringConvertible {
402
423
public var debugDescription : String {
403
424
var items = [ String] ( )
404
425
self . _storage. forEach { key, value in
405
- items. append ( " \( key. keyType. self) : \( value. description ) " )
426
+ items. append ( " \( key. keyType. self) : \( String ( describing : value) ) " )
406
427
}
407
428
return items. joined ( separator: " , " )
408
429
}
409
430
410
431
// FIXME: this currently requires that Value conforms to CustomStringConvertible which sucks
411
432
// ideally Value would conform to Equatable but that has generic requirement
412
433
// luckily, this is about to change so we can clean this up soon
434
+ /*
413
435
public static func == (lhs: ObservabilityMetadata, rhs: ObservabilityMetadata) -> Bool {
414
436
if lhs.count != rhs.count {
415
437
return false
@@ -424,7 +446,7 @@ public struct ObservabilityMetadata: Equatable, CustomDebugStringConvertible {
424
446
}
425
447
426
448
return equals
427
- }
449
+ }*/
428
450
429
451
fileprivate static func mergeLeft( _ lhs: ObservabilityMetadata ? , _ rhs: ObservabilityMetadata ? ) -> ObservabilityMetadata ? {
430
452
switch ( lhs, rhs) {
@@ -439,7 +461,7 @@ public struct ObservabilityMetadata: Equatable, CustomDebugStringConvertible {
439
461
}
440
462
}
441
463
442
- // @available(*, deprecated, message: "temporary for transition DiagnosticsEngine -> DiagnosticsEmitter")
464
+ @available ( * , deprecated, message: " temporary for transition DiagnosticsEngine -> DiagnosticsEmitter " )
443
465
public func droppingLegacyKeys( ) -> ObservabilityMetadata ? {
444
466
var metadata = ObservabilityMetadata ( )
445
467
self . forEach { ( key, value) in
@@ -467,7 +489,7 @@ public struct ObservabilityMetadata: Equatable, CustomDebugStringConvertible {
467
489
468
490
public protocol ObservabilityMetadataKey {
469
491
/// The type of value uniquely identified by this key.
470
- associatedtype Value : CustomStringConvertible
492
+ associatedtype Value
471
493
}
472
494
473
495
extension ObservabilityMetadata . AnyKey : Hashable {
@@ -480,18 +502,45 @@ extension ObservabilityMetadata.AnyKey: Hashable {
480
502
}
481
503
}
482
504
505
+ extension ObservabilityMetadata {
506
+ public var underlyingError : Error ? {
507
+ get {
508
+ self [ UnderlyingErrorKey . self]
509
+ }
510
+ set {
511
+ self [ UnderlyingErrorKey . self] = newValue
512
+ }
513
+ }
514
+
515
+ private enum UnderlyingErrorKey : Key {
516
+ typealias Value = Error
517
+ }
518
+
519
+ public struct UnderlyingError : CustomStringConvertible {
520
+ let underlying : Error
521
+
522
+ public init ( _ underlying: Error ) {
523
+ self . underlying = underlying
524
+ }
525
+
526
+ public var description : String {
527
+ String ( describing: self . underlying)
528
+ }
529
+ }
530
+ }
531
+
483
532
// MARK: - Compatibility with TSC Diagnostics APIs
484
533
485
- // @available(*, deprecated, message: "temporary for transition DiagnosticsEngine -> DiagnosticsEmitter")
534
+ @available ( * , deprecated, message: " temporary for transition DiagnosticsEngine -> DiagnosticsEmitter " )
486
535
extension ObservabilityScope {
487
536
public func makeDiagnosticsEngine( ) -> DiagnosticsEngine {
488
537
return . init( handlers: [ { Diagnostic ( $0) . map { self . diagnosticsHandler. handleDiagnostic ( scope: self , diagnostic: $0) } } ] )
489
538
}
490
539
}
491
540
492
- // @available(*, deprecated, message: "temporary for transition DiagnosticsEngine -> DiagnosticsEmitter")
541
+ @available ( * , deprecated, message: " temporary for transition DiagnosticsEngine -> DiagnosticsEmitter " )
493
542
extension Diagnostic {
494
- init ? ( _ diagnostic: TSCDiagnostic ) {
543
+ init ? ( _ diagnostic: TSCBasic . Diagnostic ) {
495
544
var metadata = ObservabilityMetadata ( )
496
545
if !( diagnostic. location is UnknownLocation ) {
497
546
metadata. legacyDiagnosticLocation = . init( diagnostic. location)
@@ -531,7 +580,7 @@ extension ObservabilitySystem {
531
580
}
532
581
533
582
@available ( * , deprecated, message: " temporary for transition DiagnosticsEngine -> DiagnosticsEmitter " )
534
- extension TSCDiagnostic {
583
+ extension TSCBasic . Diagnostic {
535
584
public init ( _ diagnostic: Diagnostic ) {
536
585
let location : DiagnosticLocation
537
586
if let legacyLocation = diagnostic. metadata? . legacyDiagnosticLocation {
@@ -560,7 +609,7 @@ extension TSCDiagnostic {
560
609
}
561
610
}
562
611
563
- // @available(*, deprecated, message: "temporary for transition DiagnosticsEngine -> DiagnosticsEmitter")
612
+ @available ( * , deprecated, message: " temporary for transition DiagnosticsEngine -> DiagnosticsEmitter " )
564
613
extension ObservabilityMetadata {
565
614
public var legacyDiagnosticLocation : DiagnosticLocationWrapper ? {
566
615
get {
@@ -588,7 +637,7 @@ extension ObservabilityMetadata {
588
637
}
589
638
}
590
639
591
- // @available(*, deprecated, message: "temporary for transition DiagnosticsEngine -> DiagnosticsEmitter")
640
+ @available ( * , deprecated, message: " temporary for transition DiagnosticsEngine -> DiagnosticsEmitter " )
592
641
extension ObservabilityMetadata {
593
642
var legacyDiagnosticData : DiagnosticDataWrapper ? {
594
643
get {
0 commit comments