Skip to content

Commit 4c050a3

Browse files
authored
Merge pull request #101 from tonystone/fixed-protected-data
Add protected data monitoring for fixed FileWriter strategy on iOS
2 parents 60c947b + 76e258b commit 4c050a3

File tree

98 files changed

+623
-287
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

98 files changed

+623
-287
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
# Change Log
22
All significant changes to this project will be documented in this file.
33

4+
## [5.0.0-beta.3](https://github.com/tonystone/tracelog/tree/5.0.0-beta.3)
5+
6+
#### Added
7+
- Added protected data monitoring for `FileWriter.Strategy.fixed` on iOS for use with `AsyncConcurrencyModeOption.buffer(writeInterval:strategy:)`. This allows TraceLog to be started up before protected data is available on iOS.
8+
49
## [5.0.0-beta.2](https://github.com/tonystone/tracelog/tree/5.0.0-beta.2)
510

611
#### Changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
* **TextFormat** a customizable human readable text formatter useable with any `OutputStreamWriter`.
5252
* **JSONFormat** a customizable JSON string formatter usable with any `OutputStreamWriter`.
5353
- [x] Create custom output formatters for any use case.
54+
- [x] An output buffering mode to buffer output when a writer is unavailable (e.g. on iOS when protected data is not available).
5455
- [x] Multiple **concurrency modes** for writing to Writers. Settable globally or per Writer installed.
5556
* **direct** - straight through real-time logging.
5657
* **sync** - blocking queued logging.

Sources/TraceLog/ConcurrencyMode.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -164,11 +164,11 @@ public enum AsyncConcurrencyModeOption {
164164
/// will write each log entry in the buffer (in order) until the end of the
165165
/// buffer or the Writer becomes unavailable again.
166166
///
167-
/// Buffering is useful for many different use case including:
167+
/// - Remark: Buffering is useful for many different use case including:
168168
///
169-
/// E.g. In an iOS application when protected data is not available to your
169+
/// In an iOS application when protected data is not available to your
170170
/// app but you require visibility into the apps logging even during
171-
//// these times.
171+
/// these times.
172172
///
173173
/// A network writer when the network connection is unavailable for any reason.
174174
///

Sources/TraceLog/Internal/Proxies/AsyncWriterProxy.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ internal class AsyncWriterProxy: WriterProxy {
5151
switch option {
5252

5353
/// Enable buffering
54+
///
5455
case ._buffer(let writeInterval, let strategy):
5556

5657
let writeTimer = BlockTimer(deadline: .now() + writeInterval, repeating: writeInterval, queue: self.queue)
@@ -189,6 +190,7 @@ private class LogEntryQueue {
189190
}
190191

191192
/// Now add the new element
193+
///
192194
storage.append(element)
193195
}
194196

@@ -204,4 +206,3 @@ private class LogEntryQueue {
204206
return storage[0]
205207
}
206208
}
207-

Sources/TraceLog/Writers & Formatters/FileStrategy+Fixed.swift

Lines changed: 0 additions & 40 deletions
This file was deleted.
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
///
2+
/// FileStrategy+Fixed.swift
3+
///
4+
/// Copyright 2019 Tony Stone
5+
///
6+
/// Licensed under the Apache License, Version 2.0 (the "License");
7+
/// you may not use this file except in compliance with the License.
8+
/// You may obtain a copy of the License at
9+
///
10+
/// http://www.apache.org/licenses/LICENSE-2.0
11+
///
12+
/// Unless required by applicable law or agreed to in writing, software
13+
/// distributed under the License is distributed on an "AS IS" BASIS,
14+
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
/// See the License for the specific language governing permissions and
16+
/// limitations under the License.
17+
///
18+
/// Created by Tony Stone on 1/31/19.
19+
///
20+
import Foundation
21+
22+
@available(iOSApplicationExtension, unavailable)
23+
internal class FileStrategyFixed: FileStrategyManager {
24+
25+
let url: URL
26+
27+
private var stream: FileOutputStream
28+
private var available: Bool
29+
30+
init(directory: URL, fileName: String) throws {
31+
32+
self.url = directory.appendingPathComponent(fileName)
33+
self.available = isLogAvailable()
34+
self.stream = try FileOutputStream(url: url, options: [.create])
35+
36+
#if os(iOS) && !targetEnvironment(simulator)
37+
/// Note: You can create empty files with file protection in any state. You just cant write or read from them.
38+
/// We can safely create the file and set it's protection level even if not available.
39+
///
40+
try FileManager.default.setAttributes([.protectionKey : FileProtectionType.completeUntilFirstUserAuthentication], ofItemAtPath: url.path)
41+
42+
if !available {
43+
NotificationCenter.default.addObserver(forName: UIApplication.protectedDataDidBecomeAvailableNotification, object: nil, queue: nil) { (_) in
44+
if !self.available {
45+
self.available = true
46+
}
47+
}
48+
}
49+
#endif
50+
}
51+
deinit {
52+
self.stream.close()
53+
}
54+
55+
func write(_ bytes: [UInt8]) -> Result<Int, FailureReason> {
56+
57+
guard self.available
58+
else { return .failure(.unavailable) }
59+
60+
return stream.write(bytes).mapError({ self.failureReason($0) })
61+
}
62+
}
63+
64+
#if os(iOS) && !targetEnvironment(simulator)
65+
import UIKit
66+
67+
@available(iOSApplicationExtension, unavailable)
68+
func isLogAvailable() -> Bool {
69+
if !Thread.isMainThread {
70+
return DispatchQueue.main.sync {
71+
return UIApplication.shared.isProtectedDataAvailable
72+
}
73+
}
74+
return UIApplication.shared.isProtectedDataAvailable
75+
}
76+
#else
77+
78+
func isLogAvailable() -> Bool {
79+
return true
80+
}
81+
#endif

0 commit comments

Comments
 (0)