swift "print" 未出现在 STDOut 中,但当 运行 在 docker 中时,第 3 方 c 库日志会出现在 ECS 上

swift "print" doesn't appear in STDOut but 3rd party c library logs do when running in docker on ECS

所以在本地通过 xcode 进行开发或使用 SPM 编译时,控制台日志会按预期显示。

SPM 在本地一切正常

swift build --configuration release 
.build/release/Myapp # prints to console

但是当我 运行 通过 ECS 上的 docker 容器 运行 执行时(linux 我想),我没有看到生成的日志我的 Swift 代码,但我确实看到 stderr 被第 3 方库打印(即 libssl 正在打印错误)以及 shell 启动应用程序时的日志

例如:

Docker 文件

FROM swift
WORKDIR /app

COPY Package.swift ./
COPY Sources ./Sources
COPY Tests ./Tests
RUN swift package clean
RUN swift build --configuration release
RUN chmod +x start.sh
CMD ["start.sh"] # just a wrapper to see if "echo" works

在start.sh

# prints as expected
echo "hi this will print"
# nothing in the executable will print though
.build/release/MyApp

我不确定为什么它没有出现在标准输出中,但您可以这样做:

import Foundation
internal struct FileHandleOutputStream: TextOutputStream {
    private let fileHandle: FileHandle
    let encoding: String.Encoding

    init(_ fileHandle: FileHandle, encoding: String.Encoding = .utf8) {
        self.fileHandle = fileHandle
        self.encoding = encoding
    }

    mutating func write(_ string: String) {
        if let data = string.data(using: encoding) {
            fileHandle.write(data)
        }
    }
}
internal var STDERR = FileHandleOutputStream(.standardError)
internal var STDOUT = FileHandleOutputStream(.standardOutput)

这允许你做:

print("error message", to: &STDERR)

打印到标准错误。

我知道这只是一种解决方法,但总比没有好。

有同样的问题,我提交了雷达,苹果回答:

When piped to another process print is buffered, so no characters appear until the buffer is filled up. (When piped to the terminal we only buffer until we hit a newline.)

You can get the behavior you want by calling setbuf(stdout, nil) once at startup:

 import Darwin
 setbuf(stdout, nil)

使用此代码,您将覆盖所有打印,因此它将在 Linux 和 Mac Xcode 上工作。 我使用了@sam 的回复并添加了覆盖 print

import Foundation

internal var STDERR = FileHandleOutputStream(.standardError)
internal var STDOUT = FileHandleOutputStream(.standardOutput)

internal struct FileHandleOutputStream: TextOutputStream {
    private let fileHandle: FileHandle
    let encoding: String.Encoding

    init(_ fileHandle: FileHandle, encoding: String.Encoding = .utf8) {
        self.fileHandle = fileHandle
        self.encoding = encoding
    }

    mutating func write(_ string: String) {
        if let data = string.data(using: encoding) {
            fileHandle.write(data)
        }
    }
}

///
/// Override of the print so it can work with Linux and MAC
/// 
public func print(_ items: Any..., separator: String = " ", terminator: String = "\n") {
    
    let output = items.map { "\([=10=])" }.joined(separator: separator)
    
    #if os(Linux)
        print(output, to: &STDERR)
    #else
        Swift.print(output, terminator: terminator)
    #endif
}