Skip to content
This repository has been archived by the owner on Apr 20, 2024. It is now read-only.

Commit

Permalink
Merge pull request #54 from nodes-vapor/feature/improve-manual-reporting
Browse files Browse the repository at this point in the history
Allow for easier manual reporting
  • Loading branch information
steffendsommer authored Feb 14, 2019
2 parents b6ed121 + dcd2ecf commit 5ea741d
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 31 deletions.
25 changes: 20 additions & 5 deletions Sources/Bugsnag/Bugsnag.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ struct BugsnagEvent: Encodable {
let exceptions: [BugsnagException]
let metaData: BugsnagMetaData
let payloadVersion: String
let request: BugsnagRequest
let request: BugsnagRequest?
let severity: String
let unhandled = true
let user: BugsnagUser?
Expand All @@ -32,7 +32,8 @@ struct BugsnagEvent: Encodable {
app: BugsnagApp,
breadcrumbs: [BugsnagBreadcrumb],
error: Error,
httpRequest: HTTPRequest,
httpRequest: HTTPRequest? = nil,
keyFilters: [String],
metadata: [String: CustomDebugStringConvertible],
payloadVersion: String,
severity: Severity,
Expand All @@ -49,7 +50,7 @@ struct BugsnagEvent: Encodable {
].merging(metadata.mapValues { $0.debugDescription }) { a, b in b }
)
self.payloadVersion = payloadVersion
self.request = BugsnagRequest(httpRequest: httpRequest)
self.request = httpRequest.map { BugsnagRequest(httpRequest: $0, keyFilters: keyFilters) }
self.severity = severity.value
self.user = userId.map { BugsnagUser(id: $0.description) }
}
Expand Down Expand Up @@ -85,14 +86,28 @@ struct BugsnagRequest: Encodable {
let referer: String
let url: String

init(httpRequest: HTTPRequest) {
self.body = httpRequest.body.data.flatMap { String(data: $0, encoding: .utf8) }
init(httpRequest: HTTPRequest, keyFilters: [String]) {
self.body = BugsnagRequest.filter(httpRequest.body, using: keyFilters)
self.clientIp = httpRequest.remotePeer.hostname
self.headers = Dictionary(httpRequest.headers.map { $0 }) { first, second in second }
self.httpMethod = httpRequest.method.string
self.referer = httpRequest.remotePeer.description
self.url = httpRequest.urlString
}

static private func filter(_ body: HTTPBody, using filters: [String]) -> String? {
guard
let data = body.data,
let unwrap = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
let jsonObject = unwrap
else {
return body.data.flatMap { String(data: $0, encoding: .utf8) }
}

let filtered = jsonObject.filter { !filters.contains($0.key) }
let json = try? JSONSerialization.data(withJSONObject: filtered, options: [.prettyPrinted])
return json.flatMap { String(data: $0, encoding: .utf8) }
}
}

struct BugsnagThread: Encodable {
Expand Down
3 changes: 3 additions & 0 deletions Sources/Bugsnag/BugsnagConfig.swift
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
public struct BugsnagConfig {
let apiKey: String
let releaseStage: String
let keyFilters: [String]
let shouldReport: Bool
let debug: Bool

public init(
apiKey: String,
releaseStage: String,
keyFilters: [String] = [],
shouldReport: Bool = true,
debug: Bool = false
) {
self.apiKey = apiKey
self.releaseStage = releaseStage
self.keyFilters = keyFilters
self.shouldReport = shouldReport
self.debug = debug
}
Expand Down
33 changes: 18 additions & 15 deletions Sources/Bugsnag/BugsnagReporter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,17 @@ public struct BugsnagReporter: Service {
version: "3"
)
private let payloadVersion = "4"
private let sendReport: (String, HTTPHeaders, Data, Request) -> Future<HTTPResponse>
private let sendReport: (String, HTTPHeaders, Data, Container) -> Future<HTTPResponse>

public init(
config: BugsnagConfig,
sendReport: ((String, HTTPHeaders, Data, Request) -> Future<HTTPResponse>)? = nil
sendReport: ((String, HTTPHeaders, Data, Container) -> Future<HTTPResponse>)? = nil
) {
self.config = config

self.sendReport = sendReport ?? { (hostName, headers, body, req) in
self.sendReport = sendReport ?? { (hostName, headers, body, container) in
HTTPClient
.connect(hostname: hostName, on: req)
.connect(hostname: hostName, on: container)
.flatMap(to: HTTPResponse.self) { client in
client.send(.init(method: .POST, headers: headers, body: body))
}
Expand All @@ -42,22 +42,25 @@ public struct BugsnagReporter: Service {

extension BugsnagReporter: ErrorReporter {
private func buildBody(
_ req: Request,
_ container: Container,
error: Error,
severity: Severity,
userId: CustomStringConvertible?,
metadata: [String: CustomDebugStringConvertible],
stacktrace: BugsnagStacktrace
) throws -> Data {
let breadcrumbs: [BugsnagBreadcrumb] = (try? req.privateContainer
let req = container as? Request
let breadcrumbsContainer = req?.privateContainer ?? container
let breadcrumbs: [BugsnagBreadcrumb] = (try? breadcrumbsContainer
.make(BreadcrumbContainer.self))?
.breadcrumbs ?? []

let event = BugsnagEvent(
app: app,
breadcrumbs: breadcrumbs,
error: error,
httpRequest: req.http,
httpRequest: req?.http,
keyFilters: config.keyFilters,
metadata: metadata,
payloadVersion: payloadVersion,
severity: severity,
Expand All @@ -77,22 +80,22 @@ extension BugsnagReporter: ErrorReporter {
@discardableResult
public func report(
_ error: Error,
severity: Severity,
userId: CustomStringConvertible?,
metadata: [String: CustomDebugStringConvertible],
severity: Severity = .error,
userId: CustomStringConvertible? = nil,
metadata: [String: CustomDebugStringConvertible] = [:],
file: String = #file,
function: String = #function,
line: Int = #line,
column: Int = #column,
on req: Request
on container: Container
) -> Future<Void> {
guard config.shouldReport else {
return req.future()
return container.future()
}

return Future.flatMap(on: req) {
return Future.flatMap(on: container) {
let body = try self.buildBody(
req,
container,
error: error,
severity: severity,
userId: userId,
Expand All @@ -106,7 +109,7 @@ extension BugsnagReporter: ErrorReporter {
)

return self
.sendReport(self.hostName, self.headers, body, req)
.sendReport(self.hostName, self.headers, body, container)
.do { response in
if self.config.debug {
print("Bugsnag response:")
Expand Down
6 changes: 3 additions & 3 deletions Sources/Bugsnag/ErrorReporter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public protocol ErrorReporter {
function: String,
line: Int,
column: Int,
on req: Request
on container: Container
) -> Future<Void>
}

Expand All @@ -20,7 +20,7 @@ extension ErrorReporter {
severity: Severity = .error,
userId: CustomStringConvertible? = nil,
metadata: [String: CustomDebugStringConvertible] = [:],
on req: Request,
on container: Container,
file: String = #file,
function: String = #function,
line: Int = #line,
Expand All @@ -35,7 +35,7 @@ extension ErrorReporter {
function: function,
line: line,
column: column,
on: req
on: container
)
}

Expand Down
16 changes: 8 additions & 8 deletions Tests/BugsnagTests/BugsnagTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ private class TestErrorReporter: ErrorReporter {
function: String,
line: Int,
column: Int,
req: Request
container: Container
)?
func report(
_ error: Error,
Expand All @@ -44,7 +44,7 @@ private class TestErrorReporter: ErrorReporter {
function: String,
line: Int,
column: Int,
on req: Request
on container: Container
) -> Future<Void> {
capturedReportParameters = (
error,
Expand All @@ -55,9 +55,9 @@ private class TestErrorReporter: ErrorReporter {
function,
line,
column,
req
container
)
return req.future()
return container.future()
}
}

Expand Down Expand Up @@ -108,14 +108,14 @@ final class BugsnagTests: XCTestCase {
host: String,
headers: HTTPHeaders,
body: Data,
request: Request
container: Container
)?

let reporter = BugsnagReporter(
config: .init(apiKey: "apiKey", releaseStage: "test"),
sendReport: { host, headers, data, request in
capturedSendReportParameters = (host, headers, data, request)
return request.future(HTTPResponse(status: .ok))
sendReport: { host, headers, data, container in
capturedSendReportParameters = (host, headers, data, container)
return container.future(HTTPResponse(status: .ok))
})
let application = try Application.test()
let request = Request(using: application)
Expand Down

0 comments on commit 5ea741d

Please sign in to comment.