Skip to content

Commit 5822ae0

Browse files
authored
Offline support
1 parent e32ca9b commit 5822ae0

32 files changed

+921
-158
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ xcuserdata/
2121
*.moved-aside
2222
*.xccheckout
2323
*.xcscmblueprint
24+
.DS_Store
2425

2526
## Obj-C/Swift specific
2627
*.hmap

Backtrace.podspec

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
Pod::Spec.new do |s|
1010

1111
s.name = "Backtrace"
12-
s.version = "1.0.0"
12+
s.version = "1.1.0"
1313
s.summary = "Backtrace's integration with iOS and macOS"
1414
s.description = "Backtrace's integration with iOS and macOS for handling crashes"
1515
s.homepage = "https://backtrace.io/"
@@ -27,7 +27,7 @@ Pod::Spec.new do |s|
2727
s.osx.public_header_files = ["Backtrace-macOS/**/*.h*"]
2828

2929
s.dependency "Backtrace-PLCrashReporter"
30-
30+
s.resources = 'Sources/**/*.xcdatamodeld'
3131

3232
s.swift_version = '4.0'
3333
end

Backtrace.xcodeproj/project.pbxproj

Lines changed: 73 additions & 6 deletions
Large diffs are not rendered by default.

Example-iOS-ObjC/AppDelegate.m

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#import "AppDelegate.h"
22
@import Backtrace;
33

4-
@interface AppDelegate ()
4+
@interface AppDelegate () <BacktraceClientDelegate>
55

66
@end
77

@@ -12,6 +12,8 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(
1212
initWithEndpoint: [NSURL URLWithString: @"https://backtrace.io"]
1313
token: @""];
1414
[BacktraceClient.shared registerWithCredentials: credentials];
15+
16+
BacktraceClient.shared.delegate = self;
1517

1618
// sending NSException
1719
@try {
@@ -34,4 +36,25 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(
3436
return YES;
3537
}
3638

39+
#pragma mark - BacktraceClientDelegate
40+
- (BacktraceCrashReport *)willSend:(BacktraceCrashReport *)report {
41+
return report;
42+
}
43+
44+
- (void)serverDidFail:(NSError *)error {
45+
46+
}
47+
48+
- (void)serverDidResponse:(BacktraceResult *)result {
49+
50+
}
51+
52+
- (NSURLRequest *)willSendRequest:(NSURLRequest *)request {
53+
return request;
54+
}
55+
56+
- (void)didReachLimit:(BacktraceResult *)result {
57+
58+
}
59+
3760
@end

Example-iOS/AppDelegate.swift

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
1919
let backtraceCredentials = BacktraceCredentials(endpoint: URL(string: "https://backtrace.io")!,
2020
token: "")
2121
BacktraceClient.shared.register(credentials: backtraceCredentials)
22+
BacktraceClient.shared.delegate = self
2223

2324
do {
2425
try throwingFunc()
@@ -31,3 +32,25 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
3132
return true
3233
}
3334
}
35+
36+
extension AppDelegate: BacktraceClientDelegate {
37+
func willSend(_ report: BacktraceCrashReport) -> (BacktraceCrashReport) {
38+
return report
39+
}
40+
41+
func willSendRequest(_ request: URLRequest) -> URLRequest {
42+
return request
43+
}
44+
45+
func serverDidFail(_ error: Error) {
46+
47+
}
48+
49+
func serverDidResponse(_ result: BacktraceResult) {
50+
51+
}
52+
53+
func didReachLimit(_ result: BacktraceResult) {
54+
55+
}
56+
}

README.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,46 @@ BacktraceClient.shared.register(credentials: BacktraceCredentials)
123123
[[BacktraceClient shared] registerWithCredentials: BacktraceCredentials];
124124
```
125125
126+
## Backtrace client configuration
127+
For more advanced usage of BacktraceClient, you can supply BacktraceClientConfiguration as a parameter. See the following example:
128+
```swift
129+
let backtraceCredentials = BacktraceCredentials(endpoint: URL(string: "backtrace_endpoint_url")!,
130+
token: "token")
131+
let backtraceConfiguration = BacktraceClientConfiguration(credentials: backtraceCredentials,
132+
dbSettings: BacktraceDatabaseSettings(),
133+
reportsPerMin: 10)
134+
BacktraceClient.shared.register(configuration: backtraceConfiguration)
135+
```
136+
137+
### Database settings
138+
BacktraceClient allows you to customize the initialization of BacktraceDatabase for local storage of error reports by supplying a BacktraceDatabaseSettings parameter, as follows:
139+
```swift
140+
let backtraceCredentials = BacktraceCredentials(endpoint: URL(string: "backtrace_endpoint_url")!,
141+
token: "token")
142+
let backtraceDatabaseSettings = BacktraceDatabaseSettings()
143+
backtraceDatabaseSettings.maxRecordCount = 1000
144+
backtraceDatabaseSettings.maxDatabaseSize = 10
145+
backtraceDatabaseSettings.retryInterval = 5
146+
backtraceDatabaseSettings.retryLimit = 3
147+
backtraceDatabaseSettings.retryBehaviour = RetryBehaviour.interval
148+
backtraceDatabaseSettings.retryOrder = RetryOder.queue
149+
let backtraceConfiguration = BacktraceClientConfiguration(credentials: backtraceCredentials,
150+
dbSettings: backtraceDatabaseSettings,
151+
reportsPerMin: 10)
152+
BacktraceClient.shared.register(configuration: backtraceConfiguration)
153+
```
154+
155+
### Events handling
156+
BacktraceClient allows you to subscribe for events produced before and after sending error report:
157+
- Swift
158+
```swift
159+
func willSend(_ report: BacktraceCrashReport) -> (BacktraceCrashReport)
160+
func willSendRequest(_ request: URLRequest) -> URLRequest
161+
func serverDidFail(_ error: Error)
162+
func serverDidResponse(_ result: BacktraceResult)
163+
func didReachLimit(_ result: BacktraceResult)
164+
```
165+
126166
## Sending an error report <a name="documentation-sending-report"></a>
127167
Registered `BacktraceClient` will be able to send an crash reports. Error report is automatically generated based.
128168

Sources/Client/BacktraceRegisteredClient.swift

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,27 +4,39 @@ class BacktraceRegisteredClient {
44

55
private let reporter: CrashReporting
66
private var networkClient: NetworkClientType
7-
private let repository = InMemoryRepository<BacktraceCrashReport>()
8-
9-
init(reporter: CrashReporting = CrashReporter(), networkClient: NetworkClientType) {
7+
private let repository: PersistentRepository<BacktraceCrashReport>
8+
private let watcher: BacktraceWatcher<PersistentRepository<BacktraceCrashReport>>
9+
10+
init(reporter: CrashReporting = CrashReporter(),
11+
networkClient: NetworkClientType,
12+
dbSettings: BacktraceDatabaseSettings,
13+
reportsPerMin: Int) throws {
1014
self.reporter = reporter
1115
self.networkClient = networkClient
16+
self.repository = try PersistentRepository<BacktraceCrashReport>(settings: dbSettings)
17+
self.watcher = try BacktraceWatcher(settings: dbSettings,
18+
reportsPerMin: reportsPerMin,
19+
networkClient: networkClient,
20+
repository: repository)
1221
}
1322
}
1423

1524
extension BacktraceRegisteredClient: BacktraceClientType {
1625

1726
func handlePendingCrashes() throws {
27+
// always try to remove pending crash report from disk
28+
defer { try? reporter.purgePendingCrashReport() }
29+
30+
// enable crash reporting
1831
try reporter.enableCrashReporting()
32+
33+
// try to send pending crash report
1934
guard reporter.hasPendingCrashes() else {
2035
BacktraceLogger.debug("No pending crashes")
2136
return
2237
}
2338
let resource = try reporter.pendingCrashReport()
24-
try repository.save(resource)
25-
try networkClient.send(resource.reportData)
26-
try repository.delete(resource)
27-
try reporter.purgePendingCrashReport()
39+
_ = try send(resource)
2840
}
2941

3042
func send(_ exception: NSException? = nil) throws -> BacktraceResult {
@@ -34,9 +46,19 @@ extension BacktraceRegisteredClient: BacktraceClientType {
3446
} else {
3547
resource = try reporter.generateLiveReport()
3648
}
37-
try repository.save(resource)
38-
let result = try networkClient.send(resource.reportData)
39-
try repository.delete(resource)
40-
return result.backtraceResult
49+
return try send(resource)
50+
}
51+
52+
private func send(_ resource: BacktraceCrashReport) throws -> BacktraceResult {
53+
do {
54+
let result = try networkClient.send(resource)
55+
if result.backtraceStatus != .ok, let report = result.backtraceData {
56+
try repository.save(report)
57+
}
58+
return result
59+
} catch let error as BacktraceErrorResponse {
60+
try repository.save(resource)
61+
throw error
62+
}
4163
}
4264
}

Sources/Client/BacktraceResponse.swift

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
11
import Foundation
22

3-
struct BacktraceHtttpResponseDeserializer {
4-
let response: BacktraceResponse
3+
enum Result<T, E: Error> {
4+
case success(T)
5+
case error(E)
6+
}
7+
8+
struct BacktraceHttpResponseDeserializer {
9+
let result: Result<BacktraceResponse, BacktraceErrorResponse>
510

611
init(httpResponse: HTTPURLResponse, responseData: Data) throws {
712
let jsonDeserializer = JSONDecoder()
813
if httpResponse.isSuccess {
9-
self.response = (try jsonDeserializer.decode(BacktraceResponse.self, from: responseData))
14+
self.result = .success(try jsonDeserializer.decode(BacktraceResponse.self, from: responseData))
1015
} else {
11-
let errorResponse = try jsonDeserializer.decode(BacktraceErrorResponse.self, from: responseData)
12-
throw errorResponse
16+
self.result = .error(try jsonDeserializer.decode(BacktraceErrorResponse.self, from: responseData))
1317
}
1418
}
1519
}
@@ -27,8 +31,8 @@ struct BacktraceResponse: Codable {
2731
}
2832

2933
extension BacktraceResponse {
30-
var backtraceResult: BacktraceResult {
31-
return BacktraceResult(.ok(response: response))
34+
func result(backtraceReport: BacktraceCrashReport) -> BacktraceResult {
35+
return BacktraceResult(.ok, message: "Ok.", backtraceReport: backtraceReport)
3236
}
3337
}
3438

@@ -42,8 +46,8 @@ struct BacktraceErrorResponse: Codable, BacktraceError {
4246
}
4347

4448
extension BacktraceErrorResponse {
45-
var backtraceResult: BacktraceResult {
46-
return BacktraceResult(.serverError(message: error.message, code: error.code))
49+
func result(backtraceReport: BacktraceCrashReport) -> BacktraceResult {
50+
return BacktraceResult(.serverError, message: error.message, backtraceReport: backtraceReport)
4751
}
4852
}
4953

Sources/Client/BacktraceUnregisteredClient.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ import Foundation
22

33
class BacktraceUnregisteredClient: BacktraceClientType {
44
private static let printBlock = { () -> BacktraceResult in
5-
BacktraceLogger.error("Backtrace client is not regiestered.")
6-
return BacktraceResult(.notRegisterd)
5+
BacktraceLogger.error("Backtrace client is not registered.")
6+
return BacktraceResult(.notRegistered, message: "Backtrace client is not registered.")
77
}
88

99
func handlePendingCrashes() throws {

Sources/Crash Reporting/CrashReporting.swift

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,12 @@ class CrashReporter: NSObject {
2222
extension CrashReporter: CrashReporting {
2323
func generateLiveReport(exception: NSException) throws -> BacktraceCrashReport {
2424
let reportData = try reporter.generateLiveReport(with: exception)
25-
let report = try PLCrashReport(data: reportData)
26-
BacktraceLogger.debug("Live report: \n\(report.info)")
27-
return BacktraceCrashReport(report: reportData, hashValue: report.uuidRef?.hashValue)
25+
return try BacktraceCrashReport(report: reportData)
2826
}
2927

3028
func generateLiveReport() throws -> BacktraceCrashReport {
3129
let reportData = try reporter.generateLiveReportAndReturnError()
32-
let report = try PLCrashReport(data: reportData)
33-
BacktraceLogger.debug("Live report: \n\(report.info)")
34-
return BacktraceCrashReport(report: reportData, hashValue: report.uuidRef?.hashValue)
30+
return try BacktraceCrashReport(report: reportData)
3531
}
3632

3733
func enableCrashReporting() throws {
@@ -40,9 +36,7 @@ extension CrashReporter: CrashReporting {
4036

4137
func pendingCrashReport() throws -> BacktraceCrashReport {
4238
let reportData = try reporter.loadPendingCrashReportDataAndReturnError()
43-
let report = try PLCrashReport(data: reportData)
44-
BacktraceLogger.debug("Pending crash: \n\(report.info)")
45-
return BacktraceCrashReport(report: reportData, hashValue: report.uuidRef?.hashValue)
39+
return try BacktraceCrashReport(report: reportData)
4640
}
4741

4842
func hasPendingCrashes() -> Bool {

0 commit comments

Comments
 (0)