Swiftpack.co - justin/jww-error-reporting as Swift Package

Swiftpack.co is a collection of thousands of indexed Swift packages. Search packages.
See all packages published by justin.
justin/jww-error-reporting 0.2.2
JWWError enables the publishing of Swift Error data to an ELK stack. Presently, this is tied exclusively to Logz.io.
⭐️ 4
🕓 50 weeks ago
iOS macOS watchOS tvOS macCatalyst
.package(url: "https://github.com/justin/jww-error-reporting.git", from: "0.2.2")

JWW Error Reporting

JWWError enables the publishing of Swift.Error data to an ELK stack. Presently, this is tied exclusively to Logz.io.

Connecting to the LogzIO service.

JWWError uses the JSON upload API provided by LogzIO to upload data. The JWWError.LogzIO type conforms to our ReportingService, which allows us to connect and send error data to the backend.

Since the error reporter is a singleton instance that runs globally through the app process, we need to configure it with the connection information after initialization using the ErrorReporterConfiguration type.

let logz: ReportingService = LogzIO(token: "your-token", region: .east, connection: .secure)
let info: AppInfoProviding = AppInfo.shared // This is made up
let configuration = ErrorReporterConfiguration(service: logz, appInfo: info)
ErrorReporter.shared.configure(configuration: logz)

Payload Format.

The logging service expects to receive the payload from

    "code": 666,
    "domain": "com.justinwme.ios.reverse-dns.filtering",
    "message": "The developer-facing message to show in Logz.io's dashboard / console",
    "environment": "qa, production, or staging",
    "reported_at": "2021-01-19T00:00:00.000Z",
    "mobile": {
        "version": "2.0.0",
        "build_number": 2500,
        "platform": "ios",
        "network": "wifi, cellular, or offline",
        "development": true
    "ios.metadata": {
        "unique": "values",
        "that": "are platform or error specific",
        "is_useful": true 
  • Code: Integer. The code associated with the error. On iOS, this would be the NSError.code.
  • Domain: String. A reverse DNS key that is unique to each specific error/report type.
  • Message: String. The non-localized message that will show up in the Kibana Dashboard.
  • Environment: String. The deployed backend environment we are targeting. Acceptable values include: QA, production, and staging.
  • Reporting Date: Date. The ISO8601-formatted date when the error was reported. Timezone should be set to UTC.
  • Mobile Info: Dictionary. A set of keys that are unique to the mobile products.
    • Version: String. The marketing version of the app reporting an error.
    • Build Number: Integer. The build number of the app reporting an error.
    • Platform: String. The app platform. The default value is "ios".
    • Network: String. The connection the app has when an error is generated. Acceptable values are: wifi, cell, or offline.
    • Development: Boolean. A boolean that is set to true if the error is reported by a local/development version of the app.
  • Platform Metadata: Dictionary. A set of keys that are unique to a given platform and/or specific error.
    • The underlying keys here are defined by each platform uniquely.
    • But think of a scenario in which you hit an error parsing JSON. You could include the JSON payload here as a key/value pair.

Reporting an Error

The error reporter supports sending any payload that conforms to ReportableError up to Kibana for analysis.

/// Protocol that declares the pieces of information necessary to report an `Error` to logstash.
public protocol ReportableError: Swift.Error {
    /// **Required**. The domain for the error.
    static var domain: String { get }

    /// The error code for the specific error type.
    var code: Int { get }

    /// A non-user-facing string describing the error.
    var message: String { get }

    /// Whether the specific instance of the error should be send to logstash for
    /// analysis. Defaults to `true`
    var isReportable: Bool { get }

    /// An object containing additional information related to the error.
    var userInfo: [ErrorPayloadKey: AnyHashable] { get }

Note the isReportable boolean: if this value is set to false, the error will be sent to the error reporter but will not be passed to Kibana itself. This is useful in scenarios when an error may occur, but reporting on it is not useful (e.g., a cancelled network request).

User Info Payloads

The userInfo dictionary that is associated with a ReportableError allows us to pass any Codable type into the error reporter, then up to Kibana. These values will be included in the JSON payload under the ios.metadata section. Currently, we are using this for passing up the JSON payload and any underlying errors that may bubble up when reporting a DecodingError.

Using the ErrorReporter.

The API to send data to Kibana through the ErrorReporter is a single call:

let additionalPayloadKey = ErrorPayloadKey("additional_payload_key")
let error = OurReportableError()
ErrorReporter.shared.post(error: error, additionalInfo: [AdditionalPayloadKey: "value"])

Of note in this API is the additionalInfo field: this allows us to affix supplemental information to the error report that may not be included in the error itself. We presently use this in the PerceptionService to ensure that we send the assessment ID and perception event data. The only requirement for the values in additionalInfo is that they must use the same signature as ReportableError.userInfo; specifically, the key is an ErrorPayloadKey with the value Hashable and Encodable.

In terms of precedence, if the same ErrorPayloadKey is included in both ReportableError.userInfo and additionalInfo, the value in additionalInfo will be used.

Known Issues and Limitations

At present, the JWWError library is not a 1.0.0 project, so there will be breaking API changes going forward. There is also plenty of missing functionality. In priority order:

  • The userInfo and additionalInfo payloads only support sending the following data types: Bool, Int, Float, Double, String, and URL. Support is missing for types such as Array, Set, and Dictionary, as well as any custom types (#12).
  • There is no API for parsing an NSError properly. This is a high priority (#13).
  • Parsing an underlying error in an NSError or URLError dictionary is not currently as readable as it should be (#14).
  • There is no validation of the keys in terms of overriding a "reserved" key (#15).
  • There is no validation to ensure that the set of "required" keys are included in each payload. This is not as urgent, since we only allow sending a full ReportableError right now (#15).
  • Somewhat related, there is no support for sending a non-error payload. We would like to support an API that just sends an arbitrary dictionary: func post(payload: [ErrorPayloadKey: AnyHashable]) (#15).
  • The LogzIO service presently only supports sending data using the secure LogzIO.Connection type. Support for streaming and insecure is pending (#16 and #17).
  • There is no feedback if an error fails to upload outside of the development console (#18).

Futher Help

If you need assistance or have questions about Kibana, ErrorReporter, or the ReportableError type, please talk to @justin.


Copyright 2021 Justin Williams. Licensed under the MIT license.


Stars: 4
Last commit: 2 weeks ago
jonrohan Something's broken? Yell at me @ptrpavlik. Praise and feedback (and money) is also welcome.

Release Notes

50 weeks ago

What's Changed

  • Set minimum OS version to 2020 releases

Full Changelog: https://github.com/justin/jww-error-reporting/compare/0.2.1...0.2.2

Swiftpack is being maintained by Petr Pavlik | @ptrpavlik | @swiftpackco | API | Analytics