CommandLineToolkit
82 строки · 3.2 Кб
1/*
2* Copyright (c) Avito Tech LLC
3*/
4
5import AtomicModels
6import DateProvider
7import CLTLoggingModels
8import Foundation
9
10public final class FileHandleLoggerHandler: LoggerHandler {
11private let dateProvider: DateProvider
12private let fileState: AtomicValue<FileState>
13private let logEntryTextFormatter: LogEntryTextFormatter
14private let fileHandleShouldBeClosed: Bool
15private let skipMetadataFlag: SkipMetadataFlags?
16private let coordinateNamesToSkipFromTextualOutput: Set<String>
17
18public enum SkipMetadataFlags: String {
19case skipStdOutput
20case skipFileOutput
21}
22
23public init(
24dateProvider: DateProvider,
25fileHandle: FileHandle,
26logEntryTextFormatter: LogEntryTextFormatter,
27fileHandleShouldBeClosed: Bool,
28skipMetadataFlag: SkipMetadataFlags?,
29coordinateNamesToSkipFromTextualOutput: Set<String> = ContextualLogger.ContextKeys.stringSetForAllRawValues()
30) {
31self.dateProvider = dateProvider
32self.fileState = AtomicValue(FileState.open(fileHandle))
33self.logEntryTextFormatter = logEntryTextFormatter
34self.fileHandleShouldBeClosed = fileHandleShouldBeClosed
35self.skipMetadataFlag = skipMetadataFlag
36self.coordinateNamesToSkipFromTextualOutput = coordinateNamesToSkipFromTextualOutput
37}
38
39public func handle(logEntry: LogEntry) {
40if let skipMetadataFlag = skipMetadataFlag, logEntry.coordinates.contains(where: { $0.name == skipMetadataFlag.rawValue }) {
41return
42}
43
44var coordinates = logEntry.coordinates.filter {
45!coordinateNamesToSkipFromTextualOutput.contains($0.name)
46}
47
48if let subprocessId = logEntry.coordinate(name: ContextualLogger.ContextKeys.subprocessId.rawValue)?.value {
49if let xcrunToolName = logEntry.coordinate(name: ContextualLogger.ContextKeys.xcrunToolName.rawValue)?.value {
50coordinates.append(LogEntryCoordinate(name: xcrunToolName, value: "\(subprocessId)"))
51} else if let subprocessName = logEntry.coordinate(name: ContextualLogger.ContextKeys.subprocessName.rawValue)?.value {
52coordinates.append(LogEntryCoordinate(name: subprocessName, value: "\(subprocessId)"))
53}
54}
55
56let logEntry = logEntry.with(coordinates: coordinates)
57
58let text = logEntryTextFormatter.format(logEntry: logEntry)
59fileState.withExclusiveAccess { fileState in
60guard var fileHandle = fileState.openedFileHandle else { return }
61print(text, to: &fileHandle)
62}
63}
64
65public func tearDownLogging(timeout: TimeInterval) {
66fileState.withExclusiveAccess { fileState in
67if fileHandleShouldBeClosed {
68fileState.close()
69}
70}
71}
72}
73
74extension ContextualLogger {
75public var skippingStdOutput: ContextualLogger {
76withMetadata(key: FileHandleLoggerHandler.SkipMetadataFlags.skipStdOutput.rawValue, value: nil)
77}
78
79public var skippingFileLogOutput: ContextualLogger {
80withMetadata(key: FileHandleLoggerHandler.SkipMetadataFlags.skipFileOutput.rawValue, value: nil)
81}
82}
83