CommandLineToolkit

Форк
0
201 строка · 6.8 Кб
1
/*
2
 * Copyright (c) Avito Tech LLC
3
 */
4

5
import DateProvider
6
import Dispatch
7
import FileSystem
8
import CLTLoggingModels
9
import Foundation
10
import Kibana
11
import KibanaModels
12
import PathLib
13
import Tmp
14

15
public final class LoggingSetup {
16
    private let dateProvider: DateProvider
17
    private let fileSystem: FileSystem
18
    private let logDomainName: String
19
    private let logFileExtension = "log"
20
    private let logFilePrefix = "pid_"
21
    private let logFilesCleanUpRegularity: TimeInterval = 10800
22
    private let aggregatedLoggerHandler: AggregatedLoggerHandler
23
    private let pluggableLoggerHandlerForKibana = RedirectingLoggerHandler()
24
    public let rootLoggerHandler: LoggerHandler
25
    
26
    public init(
27
        dateProvider: DateProvider,
28
        fileSystem: FileSystem,
29
        logDomainName: String
30
    ) {
31
        self.dateProvider = dateProvider
32
        self.fileSystem = fileSystem
33
        self.logDomainName = logDomainName
34
        self.aggregatedLoggerHandler = AggregatedLoggerHandler(handlers: [])
35
        self.rootLoggerHandler = self.aggregatedLoggerHandler
36
    }
37
    
38
    public func createLogger(
39
        stderrVerbosity: Verbosity,
40
        detailedLogVerbosity: Verbosity?,
41
        kibanaVerbosity: Verbosity
42
    ) throws -> ContextualLogger {
43
        let logger = ContextualLogger(
44
            dateProvider: dateProvider,
45
            loggerHandler: rootLoggerHandler,
46
            metadata: [:]
47
        )
48
        add(
49
            loggerHandler: createStderrInfoLoggerHandler(
50
                verbosity: stderrVerbosity
51
            )
52
        )
53
        add(
54
            loggerHandler: LimitingLoggerHandler(
55
                maximumVerbosity: kibanaVerbosity,
56
                target: pluggableLoggerHandlerForKibana
57
            )
58
        )
59
        if let detailedLogVerbosity = detailedLogVerbosity {
60
            let filename = logFilePrefix + String(ProcessInfo.processInfo.processIdentifier)
61
            let detailedLogPath = try TemporaryFile(
62
                containerPath: try logsContainerFolder(),
63
                prefix: filename,
64
                suffix: "." + logFileExtension,
65
                deleteOnDealloc: false
66
            )
67
            add(
68
                loggerHandler: createDetailedLoggerHandler(
69
                    fileHandle: detailedLogPath.fileHandleForWriting,
70
                    verbosity: detailedLogVerbosity
71
                )
72
            )
73
            logger.info("Verbose logs available at: \(detailedLogPath.absolutePath)")
74
        }
75
        
76
        return logger
77
    }
78
    
79
    public func set(
80
        kibanaConfiguration: KibanaConfiguration
81
    ) throws {
82
        let handler = KibanaLoggerHandler(
83
            kibanaClient: try HttpKibanaClient(
84
                dateProvider: dateProvider,
85
                endpoints: try kibanaConfiguration.endpoints.map { try KibanaHttpEndpoint.from(url: $0) },
86
                indexPattern: kibanaConfiguration.indexPattern,
87
                urlSession: .shared,
88
                authorization: kibanaConfiguration.authorization
89
            )
90
        )
91
        pluggableLoggerHandlerForKibana.setTarget(handler)
92
    }
93
    
94
    public func childProcessLogsContainerProvider() throws -> ChildProcessLogsContainerProvider {
95
        return ChildProcessLogsContainerProviderImpl(
96
            fileSystem: fileSystem,
97
            mainContainerPath: try logsContainerFolder()
98
        )
99
    }
100
    
101
    public func add(loggerHandler: LoggerHandler) {
102
        aggregatedLoggerHandler.append(handler: loggerHandler)
103
    }
104
    
105
    public func tearDown(timeout: TimeInterval) {
106
        aggregatedLoggerHandler.tearDownLogging(timeout: timeout)
107
    }
108
    
109
    public func cleanUpLogs(
110
        logger: ContextualLogger,
111
        logDomainName: String,
112
        olderThan date: Date,
113
        queue: OperationQueue,
114
        completion: @escaping (Error?) -> ()
115
    ) throws {
116
        let logsCleanUpMarkerFileProperties = fileSystem.properties(
117
            path: try fileSystem.logsCleanUpMarkerFile(
118
                logDomainName: logDomainName
119
            )
120
        )
121
        guard dateProvider.currentDate().timeIntervalSince(
122
            try logsCleanUpMarkerFileProperties.modificationDate.get()
123
        ) > logFilesCleanUpRegularity else {
124
            logger.trace("Skipping log clean up since last clean up happened recently")
125
            return
126
        }
127
        
128
        logger.trace("Cleaning up old log files")
129
        try logsCleanUpMarkerFileProperties.touch()
130
        
131
        let logsEnumerator = fileSystem.contentEnumerator(
132
            forPath: try fileSystem.logsFolder(
133
                logDomainName: logDomainName
134
            ),
135
            style: .deep
136
        )
137

138
        queue.addOperation {
139
            do {
140
                try logsEnumerator.each { (path: AbsolutePath) in
141
                    guard path.extension == self.logFileExtension else { return }
142
                    let modificationDate = try self.fileSystem.properties(path: path).modificationDate.get()
143
                    if modificationDate < date {
144
                        do {
145
                            try self.fileSystem.delete(path: path)
146
                        } catch {
147
                            logger.error("Failed to remove old log file at \(path): \(error)")
148
                        }
149
                    }
150
                }
151
                completion(nil)
152
            } catch {
153
                completion(error)
154
            }
155
        }
156
    }
157
    
158
    private func createStderrInfoLoggerHandler(
159
        verbosity: Verbosity
160
    ) -> LoggerHandler {
161
        return LimitingLoggerHandler(
162
            maximumVerbosity: verbosity,
163
            target: FileHandleLoggerHandler(
164
                dateProvider: dateProvider,
165
                fileHandle: FileHandle.standardError,
166
                logEntryTextFormatter: NSLogLikeLogEntryTextFormatter(
167
                    logLocation: false,
168
                    logCoordinates: false
169
                ),
170
                fileHandleShouldBeClosed: false,
171
                skipMetadataFlag: .skipStdOutput
172
            )
173
        )
174
    }
175
    
176
    private func createDetailedLoggerHandler(
177
        fileHandle: FileHandle,
178
        verbosity: Verbosity
179
    ) -> LoggerHandler {
180
        return LimitingLoggerHandler(
181
            maximumVerbosity: verbosity,
182
            target: FileHandleLoggerHandler(
183
                dateProvider: dateProvider,
184
                fileHandle: fileHandle,
185
                logEntryTextFormatter: NSLogLikeLogEntryTextFormatter(
186
                    logLocation: true,
187
                    logCoordinates: true
188
                ),
189
                fileHandleShouldBeClosed: true,
190
                skipMetadataFlag: .skipFileOutput
191
            )
192
        )
193
    }
194
    
195
    private func logsContainerFolder() throws -> AbsolutePath {
196
        try fileSystem.folderForStoringLogs(
197
            logDomainName: logDomainName,
198
            processName: ProcessInfo.processInfo.processName
199
        )
200
    }
201
}
202

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.