@@ -39,11 +39,24 @@ public struct JSONLogger : LogHandler {
3939
4040 public static let defaultJSONEncoder : JSONEncoder = {
4141 let res = JSONEncoder ( )
42- #if swift(>=5.3)
43- res. outputFormatting = [ . withoutEscapingSlashes]
42+ #if canImport(Darwin) || swift(>=5.3)
43+ if #available( macOS 10 . 15 , tvOS 13 . 0 , iOS 13 . 0 , watchOS 6 . 0 , * ) {
44+ res. outputFormatting = [ . withoutEscapingSlashes]
45+ }
4446#endif
4547 res. keyEncodingStrategy = . useDefaultKeys
46- res. dateEncodingStrategy = . iso8601
48+ if #available( macOS 10 . 12 , tvOS 10 . 0 , iOS 10 . 0 , watchOS 3 . 0 , * ) {
49+ res. dateEncodingStrategy = . iso8601
50+ } else {
51+ res. dateEncodingStrategy = . formatted( {
52+ /* Technically an RFC3339 date formatter (straight from the doc), but compatible with ISO8601. */
53+ let ret = DateFormatter ( )
54+ ret. locale = Locale ( identifier: " en_US_POSIX " )
55+ ret. dateFormat = " yyyy-MM-dd'T'HH:mm:ssZZZZZ "
56+ ret. timeZone = TimeZone ( secondsFromGMT: 0 )
57+ return ret
58+ } ( ) )
59+ }
4760 res. dataEncodingStrategy = . base64
4861 res. nonConformingFloatEncodingStrategy = . convertToString( positiveInfinity: " +inf " , negativeInfinity: " -inf " , nan: " nan " )
4962 return res
@@ -52,22 +65,24 @@ public struct JSONLogger : LogHandler {
5265#if swift(>=5.7)
5366 public static let defaultJSONCodersForStringConvertibles : ( JSONEncoder , JSONDecoder ) = {
5467 let encoder = JSONEncoder ( )
55- encoder. outputFormatting = [ . withoutEscapingSlashes]
68+ if #available( macOS 10 . 15 , tvOS 13 . 0 , iOS 13 . 0 , watchOS 6 . 0 , * ) {
69+ encoder. outputFormatting = [ . withoutEscapingSlashes]
70+ }
5671 encoder. keyEncodingStrategy = . useDefaultKeys
5772 encoder. dateEncodingStrategy = . iso8601
5873 encoder. dataEncodingStrategy = . base64
5974 encoder. nonConformingFloatEncodingStrategy = . throw
6075 let decoder = JSONDecoder ( )
6176 /* #if os(Darwin) is not available on this version of the compiler. */
62- #if !os(Linux )
77+ #if canImport(Darwin) || swift(>=6.0 )
6378 if #available( macOS 12 . 0 , tvOS 15 . 0 , iOS 15 . 0 , watchOS 8 . 0 , * ) {
6479 decoder. allowsJSON5 = false
6580 }
6681#endif
6782 decoder. keyDecodingStrategy = . useDefaultKeys
6883 decoder. dateDecodingStrategy = . iso8601
6984 decoder. dataDecodingStrategy = . base64
70- #if !os(Linux )
85+ #if canImport(Darwin) || swift(>=6.0 )
7186 if #available( macOS 12 . 0 , tvOS 15 . 0 , iOS 15 . 0 , watchOS 8 . 0 , * ) {
7287 decoder. assumesTopLevelDictionary = false
7388 }
@@ -210,7 +225,7 @@ public struct JSONLogger : LogHandler {
210225 }
211226 let lineDataNoSeparator = prefix + jsonLine + suffix
212227
213- /* We lock, because the writeAll function might split the write in more than 1 write
228+ /* We lock, because the write(contentsOf:) function might split the write in more than 1 write
214229 * (if the write system call only writes a part of the data).
215230 * If another part of the program writes to fd, we might get interleaved data,
216231 * because they cannot be aware of our lock (and we cannot be aware of theirs if they have one). */
@@ -222,7 +237,48 @@ public struct JSONLogger : LogHandler {
222237 /* Is the write retried on interrupt?
223238 * We’ll assume yes, but we don’t and can’t know for sure
224239 * until FileHandle has been migrated to the open-source Foundation. */
225- _ = try ? outputFileHandle. write ( contentsOf: interLogData + lineDataNoSeparator)
240+ let data = interLogData + lineDataNoSeparator
241+ /* Is there a better idea than silently drop the message in case of fail? */
242+ /* Is the write retried on interrupt?
243+ * We’ll assume yes, but we don’t and can’t know for sure
244+ * until FileHandle has been migrated to the open-source Foundation. */
245+ if #available( macOS 10 . 15 . 4 , tvOS 13 . 4 , iOS 13 . 4 , watchOS 6 . 2 , * ) {
246+ #if swift(>=5.2) || !canImport(Darwin)
247+ _ = try ? outputFileHandle. write ( contentsOf: data)
248+ #else
249+ /* Let’s write “manually” (FileHandle’s write(_:) method throws an ObjC exception in case of an error).
250+ * This code is copied below. */
251+ data. withUnsafeBytes { bytes in
252+ guard !bytes. isEmpty else {
253+ return
254+ }
255+ var written : Int = 0
256+ repeat {
257+ written += write (
258+ outputFileHandle. fileDescriptor,
259+ bytes. baseAddress!. advanced ( by: written) ,
260+ bytes. count - written
261+ )
262+ } while written < bytes. count && ( errno == EINTR || errno == EAGAIN)
263+ }
264+ #endif
265+ } else {
266+ /* Let’s write “manually” (FileHandle’s write(_:) method throws an ObjC exception in case of an error).
267+ * This is a copy of the code just above. */
268+ data. withUnsafeBytes { bytes in
269+ guard !bytes. isEmpty else {
270+ return
271+ }
272+ var written : Int = 0
273+ repeat {
274+ written += write (
275+ outputFileHandle. fileDescriptor,
276+ bytes. baseAddress!. advanced ( by: written) ,
277+ bytes. count - written
278+ )
279+ } while written < bytes. count && ( errno == EINTR || errno == EAGAIN)
280+ }
281+ }
226282 }
227283 }
228284
0 commit comments