1// SPDX-FileCopyrightText: 2025 The Project Pterodactyl Developers 2// 3// SPDX-License-Identifier: MPL-2.0 4 5import Foundation 6import Logging 7 8struct FileLogHandler: LogHandler { 9 private let label: String 10 private let fileHandle: FileHandle 11 var logLevel: Logger.Level = .info 12 var metadata: Logger.Metadata = [:] 13 14 init(label: String, fileURL: URL) { 15 self.label = label 16 17 // Ensure file exists 18 if !FileManager.default.fileExists(atPath: fileURL.path) { 19 FileManager.default.createFile(atPath: fileURL.path, contents: nil) 20 } 21 22 // Open file for updating (read/write) 23 self.fileHandle = try! FileHandle(forUpdating: fileURL) 24 self.fileHandle.seekToEndOfFile() 25 } 26 27 subscript(metadataKey key: String) -> Logger.Metadata.Value? { 28 get { metadata[key] } 29 set { metadata[key] = newValue } 30 } 31 32 func log( 33 level: Logger.Level, 34 message: Logger.Message, 35 metadata: Logger.Metadata?, 36 source: String, 37 file: String, 38 function: String, 39 line: UInt 40 ) { 41 var fullMetadata = self.metadata 42 metadata?.forEach { fullMetadata[$0] = $1 } 43 44 let line = "[\(level)] \(message)\n" 45 if let data = line.data(using: .utf8) { 46 fileHandle.write(data) 47 } 48 } 49} 50 51extension Logger { 52 static let shared: Self = { 53 let logFile = URL(fileURLWithPath: "/tmp/pterodactyl-language-server.log") 54 55 LoggingSystem.bootstrap { label in 56 FileLogHandler(label: label, fileURL: logFile) 57 } 58 59 var logger = Logger(label: "org.pterodactyl.language-server") 60 logger.logLevel = .debug 61 return logger 62 }() 63}