From cef221478622e9e3f7ecd6ae19cc0f4407ca4d2e Mon Sep 17 00:00:00 2001 From: Felipe Jin Date: Sun, 4 Apr 2021 21:48:09 +0100 Subject: [PATCH 1/3] Improve StdioOutputStream with fwrite (#180) --- Sources/Logging/Logging.swift | 16 +++++++++++--- Tests/LoggingTests/LoggingTest+XCTest.swift | 1 + Tests/LoggingTests/LoggingTest.swift | 23 ++++++++++++++++++--- 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/Sources/Logging/Logging.swift b/Sources/Logging/Logging.swift index e76c68b3..375e9447 100644 --- a/Sources/Logging/Logging.swift +++ b/Sources/Logging/Logging.swift @@ -808,7 +808,7 @@ internal struct StdioOutputStream: TextOutputStream { internal let flushMode: FlushMode internal func write(_ string: String) { - string.withCString { ptr in + contiguousUTF8(string).withContiguousStorageIfAvailable { utf8Bytes in #if os(Windows) _lock_file(self.file) #elseif canImport(WASILibc) @@ -825,11 +825,11 @@ internal struct StdioOutputStream: TextOutputStream { funlockfile(self.file) #endif } - _ = fputs(ptr, self.file) + _ = fwrite(utf8Bytes.baseAddress!, 1, utf8Bytes.count, self.file) if case .always = self.flushMode { self.flush() } - } + }! } /// Flush the underlying stream. @@ -838,6 +838,16 @@ internal struct StdioOutputStream: TextOutputStream { _ = fflush(self.file) } + internal func contiguousUTF8(_ string: String) -> String.UTF8View { + var contiguousString = string + #if compiler(>=5.1) + contiguousString.makeContiguousUTF8() + #else + contiguousString = string + "" + #endif + return contiguousString.utf8 + } + internal static let stderr = StdioOutputStream(file: systemStderr, flushMode: .always) internal static let stdout = StdioOutputStream(file: systemStdout, flushMode: .always) diff --git a/Tests/LoggingTests/LoggingTest+XCTest.swift b/Tests/LoggingTests/LoggingTest+XCTest.swift index ecf0466d..e4cfc695 100644 --- a/Tests/LoggingTests/LoggingTest+XCTest.swift +++ b/Tests/LoggingTests/LoggingTest+XCTest.swift @@ -51,6 +51,7 @@ extension LoggingTest { ("testStreamLogHandlerOutputFormat", testStreamLogHandlerOutputFormat), ("testStreamLogHandlerOutputFormatWithMetaData", testStreamLogHandlerOutputFormatWithMetaData), ("testStreamLogHandlerOutputFormatWithOrderedMetadata", testStreamLogHandlerOutputFormatWithOrderedMetadata), + ("testStdioOutputStreamWrite", testStdioOutputStreamWrite), ("testStdioOutputStreamFlush", testStdioOutputStreamFlush), ("testOverloadingError", testOverloadingError), ] diff --git a/Tests/LoggingTests/LoggingTest.swift b/Tests/LoggingTests/LoggingTest.swift index e1d2817f..974c3b1d 100644 --- a/Tests/LoggingTests/LoggingTest.swift +++ b/Tests/LoggingTests/LoggingTest.swift @@ -723,6 +723,23 @@ class LoggingTest: XCTestCase { XCTAssert(interceptStream.strings[1].contains("a=a1 b=b1")) } + func testStdioOutputStreamWrite() { + self.withWriteReadFDsAndReadBuffer { writeFD, readFD, readBuffer in + let logStream = StdioOutputStream(file: writeFD, flushMode: .always) + LoggingSystem.bootstrapInternal { StreamLogHandler(label: $0, stream: logStream) } + let log = Logger(label: "test") + let testString = "hello\u{0} world" + log.critical("\(testString)") + + let size = read(readFD, readBuffer, 256) + + let output = String(decoding: UnsafeRawBufferPointer(start: UnsafeRawPointer(readBuffer), count: size), as: UTF8.self) + let messageSucceeded = output.trimmingCharacters(in: .whitespacesAndNewlines).hasSuffix(testString) + XCTAssertTrue(messageSucceeded) + + } + } + func testStdioOutputStreamFlush() { // flush on every statement self.withWriteReadFDsAndReadBuffer { writeFD, readFD, readBuffer in @@ -756,7 +773,7 @@ class LoggingTest: XCTestCase { var fds: [Int32] = [-1, -1] fds.withUnsafeMutableBufferPointer { ptr in let err = pipe(ptr.baseAddress!) - XCTAssertEqual(err, 0, "pipe faild \(err)") + XCTAssertEqual(err, 0, "pipe failed \(err)") } let writeFD = fdopen(fds[1], "w") @@ -767,11 +784,11 @@ class LoggingTest: XCTestCase { } var err = setvbuf(writeFD, writeBuffer, _IOFBF, 256) - XCTAssertEqual(err, 0, "setvbuf faild \(err)") + XCTAssertEqual(err, 0, "setvbuf failed \(err)") let readFD = fds[0] err = fcntl(readFD, F_SETFL, fcntl(readFD, F_GETFL) | O_NONBLOCK) - XCTAssertEqual(err, 0, "fcntl faild \(err)") + XCTAssertEqual(err, 0, "fcntl failed \(err)") let readBuffer = UnsafeMutablePointer.allocate(capacity: 256) defer { From 885573524cb121a15e3804325a1248fd39a2037b Mon Sep 17 00:00:00 2001 From: Johannes Weiss Date: Tue, 6 Apr 2021 11:55:32 +0100 Subject: [PATCH 2/3] update formatting --- Sources/Logging/Logging.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Logging/Logging.swift b/Sources/Logging/Logging.swift index 375e9447..ef8b9953 100644 --- a/Sources/Logging/Logging.swift +++ b/Sources/Logging/Logging.swift @@ -808,7 +808,7 @@ internal struct StdioOutputStream: TextOutputStream { internal let flushMode: FlushMode internal func write(_ string: String) { - contiguousUTF8(string).withContiguousStorageIfAvailable { utf8Bytes in + self.contiguousUTF8(string).withContiguousStorageIfAvailable { utf8Bytes in #if os(Windows) _lock_file(self.file) #elseif canImport(WASILibc) From 73bbfa9e4b32038c0a449c1b2ca683eeb9631d56 Mon Sep 17 00:00:00 2001 From: Johannes Weiss Date: Tue, 6 Apr 2021 11:56:02 +0100 Subject: [PATCH 3/3] updated test formatting --- Tests/LoggingTests/LoggingTest.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/Tests/LoggingTests/LoggingTest.swift b/Tests/LoggingTests/LoggingTest.swift index 974c3b1d..e23b42e3 100644 --- a/Tests/LoggingTests/LoggingTest.swift +++ b/Tests/LoggingTests/LoggingTest.swift @@ -736,7 +736,6 @@ class LoggingTest: XCTestCase { let output = String(decoding: UnsafeRawBufferPointer(start: UnsafeRawPointer(readBuffer), count: size), as: UTF8.self) let messageSucceeded = output.trimmingCharacters(in: .whitespacesAndNewlines).hasSuffix(testString) XCTAssertTrue(messageSucceeded) - } }