Giter Club home page Giter Club logo

Comments (16)

kylebrowning avatar kylebrowning commented on June 28, 2024 1

Trying to create a project that reproduces this though.

from swift-log.

kylebrowning avatar kylebrowning commented on June 28, 2024

I can't seem to get this context to show up again, but for a moment, when suggesting candidates, it told me there we re two.
os.Logger and Logging.Logger

I've removed the ambiguity by using Logging.Logger, but the issue remains unless I do that

from swift-log.

weissi avatar weissi commented on June 28, 2024

@kylebrowning Correct me if I'm wrong but you are doing both import Logging and import os in the same file, correct?

from swift-log.

kylebrowning avatar kylebrowning commented on June 28, 2024

@weissi Im personally not, but a dependency might be.

import FirebaseCrashlytics
import Logging
import UIKit

from swift-log.

weissi avatar weissi commented on June 28, 2024

@kylebrowning it will be fine if a dependency does unless they do @_exported import OSLog/@_exported import os

from swift-log.

weissi avatar weissi commented on June 28, 2024

@kylebrowning seems like FirebaseCrashlytics may be doing it. This program works totally fine for me:

import UIKit
import Logging

let l: Logger? = nil
class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        l?.info("hello")
    }
}

so UIKit doesn't @_exported import OSLog/os which is good, it shouldn't but FirebaseCrashlytics may be doing that?

from swift-log.

kylebrowning avatar kylebrowning commented on June 28, 2024

I just removed import FIreBaseCrashlytics and UIKit as neither are needed, however, still the same error.

Probably because @_exported will happen if I import them from anywhere right? So It might not even be Firebase

from swift-log.

weissi avatar weissi commented on June 28, 2024

@kylebrowning can you give me the whole set of imports from the file that fails?

from swift-log.

weissi avatar weissi commented on June 28, 2024

For your error to happen that file must have (somehow) imported both OSLog/os and Logging

from swift-log.

kylebrowning avatar kylebrowning commented on June 28, 2024

Heres the whole file now

import Logging

public protocol LogListener {
    var isEnabled: Bool { get set }
    var logLevel: Logger.Level { get set }
    func logMessage(_ logDetails: ATHLogHandler.LogDetails)
}

public class ATHLogHandler: LogHandler {
    public let label: String
    // This only exists as its required by `LogHandler`
    // But we're not going to use it, as its up to the listeners
    public var logLevel: Logging.Logger.Level
    public var listeners: [LogListener]

    public struct LogDetails {
        let level: Logging.Logger.Level
        let message: Logging.Logger.Message
        let metadata: Logging.Logger.Metadata?
        let prettyMetadata: String?
        let file: String
        let function: String
        let line: UInt
        let date: Date
        let formattedMessage: String
    }

    public init(label: String, level: Logging.Logger.Level = .debug, metadata: Logging.Logger.Metadata = [:], listeners: [LogListener]) {
        self.label = label
        self.logLevel = level
        self.metadata = metadata
        self.listeners = listeners
    }

    public func log(level: Logging.Logger.Level, message: Logging.Logger.Message, metadata: Logging.Logger.Metadata?, file: String, function: String, line: UInt) {
        let date = Date()
        let dateString = DateUtils.iso8601Milliseconds.string(from: date)
        let filePath = self.conciseSourcePath(file)
        listeners.forEach { listener in
            guard listener.isEnabled else { return }
            var text = "\(dateString) [\(level)] "
            // only log metadata + file info if we are debug or trace
            if listener.logLevel <= .debug {
                text += "[\(filePath):\(Int(line))] "

                let prettyMetadata = metadata?.isEmpty ?? true
                ? self.prettyMetadata
                : self.prettify(self.metadata.merging(metadata!, uniquingKeysWith: { _, new in new }))

                if let metadata = prettyMetadata {
                     text += "[\(metadata)] "
                }
            }
            if listener.logLevel <= .trace {
                text += "[\(self.label)] "
            }
            text += message.description
            let logDetails = LogDetails(level: level, message: message, metadata: metadata, prettyMetadata: prettyMetadata, file: file, function: function, line: line, date: date, formattedMessage: text)
            listener.logMessage(logDetails)
        }
    }

    /// splits a path on the /'s
    ///
    private func conciseSourcePath(_ path: String) -> String {
        return (path as NSString).lastPathComponent
    }

    public subscript(metadataKey metadataKey: String) -> Logging.Logger.Metadata.Value? {
        get {
            return metadata[metadataKey]
        }
        set {
            metadata[metadataKey] = newValue
        }
    }

    public var metadata = Logger.Metadata() {
        didSet {
            prettyMetadata = prettify(metadata)
        }
    }

    private var prettyMetadata: String?

    private func prettify(_ metadata: Logging.Logger.Metadata) -> String? {
        return !metadata.isEmpty ? metadata.map { "\($0)=\($1)" }.joined(separator: " ") : nil
    }
}

extension LoggingSystem {
    /// Bootstraps a `ATHLogHandler` to the `LoggingSystem`, so that logger will be used in `Logger.init(label:)`.
    ///
    ///     ATHLogHandler.boostrap()
    ///
    /// - Parameters:
    ///   - level: The minimum level of message that the logger will output. This defaults to `.debug`, the lowest level.
    ///   - metadata: Extra metadata to log with the message. This defaults to an empty dictionary.
    public static func bootstrap(level: Logging.Logger.Level = .info, metadata: Logging.Logger.Metadata = [:], listeners: [LogListener]) {
        self.bootstrap { label in
            return ATHLogHandler(label: label, level: level, metadata: metadata, listeners: listeners)
        }
    }
}

struct ATHLogging {
    private static var _log: Logging.Logger?
    static var log: Logging.Logger {
        if let logger = ATHLogging._log {
            return logger
        } else {
            let logger = Logger(label: "com.theathletic.news")
            let buildString: String = "Version: \(String.getAppVersionSemver) Build: \(String.getBuildVersion)"
            let processInfo: ProcessInfo = ProcessInfo.processInfo
            logger.info("\(processInfo.processName) \(buildString) PID: \(processInfo.processIdentifier)")
            ATHLogging._log = logger
            return logger
        }
    }
    #if APPSTORE
    // Production App Store Loggers
    static var listeners: [LogListener] = [
        CrashlyticsLogListener(isEnabled: true, logLevel: .info)
    ]
    #else
    // Development Xcode loggers
    static var listeners: [LogListener] = [
        // Change your desired level here
        AthleticLogListener(isEnabled: true, logLevel: .debug),
        CrashlyticsLogListener(isEnabled: true, logLevel: .trace)
    ]
    #endif
    static func bootstrap() {
        LoggingSystem.bootstrap(level: .trace, listeners: ATHLogging.listeners)
    }

    static func disableProductionLogging() {
        for var listener in ATHLogging.listeners {
            listener.isEnabled = false
        }
    }

    static func enableProductionLogging() {
        for var listener in ATHLogging.listeners {
            listener.isEnabled = true
        }
    }
}

private class AthleticLogListener: LogListener {
    init(isEnabled: Bool, logLevel: Logging.Logger.Level) {
        self.isEnabled = isEnabled
        self.logLevel = logLevel
    }

    var isEnabled: Bool
    var logLevel: Logging.Logger.Level
    func logMessage(_ logDetails: ATHLogHandler.LogDetails) {
        if logLevel <= logDetails.level {
            print(logDetails.formattedMessage)
        }
    }
}

private class CrashlyticsLogListener: LogListener {
    init(isEnabled: Bool, logLevel: Logging.Logger.Level) {
        self.isEnabled = isEnabled
        self.logLevel = logLevel
    }

    var isEnabled: Bool
    var logLevel: Logging.Logger.Level
    func logMessage(_ logDetails: ATHLogHandler.LogDetails) {
        if logLevel <= logDetails.level {
            crashlyticsLog(logDetails.formattedMessage)
        }
    }
}

from swift-log.

kylebrowning avatar kylebrowning commented on June 28, 2024

If I was importing both of those, wouldn't this also fail to compile on Xcode 11?

from swift-log.

weissi avatar weissi commented on June 28, 2024

@kylebrowning The new SDK adds a type Logger in the os/OSLog module. So if in the same file you have import Logging and import OSLog/os, then it'll now clash.

You clearly don't have that. The only other way I can see this fail is if you @_exported import Logging or @_exported import os or @_exported import OSLog somewhere in the same module.

from swift-log.

weissi avatar weissi commented on June 28, 2024

@kylebrowning but maybe I'm missing something. Can you create a small Xcode project that reproduces this?

from swift-log.

weissi avatar weissi commented on June 28, 2024

@kylebrowning No, the Logger type is new in this year's OSes. Xcode 11 ships the old SDKs which don't have Logger.

from swift-log.

kylebrowning avatar kylebrowning commented on June 28, 2024
❯ grep -rl "@_exported" .
./theathletic-ios.xcworkspace/xcuserdata/kylebrowning.xcuserdatad/UserInterfaceState.xcuserstate
~/Projects/ios/theathletic-ios develop *49 !1 ❯                                                                                                                                  14s 09:37:39

Nothing in my project uses @_exported. The only file that came up was my search history in Xcode.

from swift-log.

kylebrowning avatar kylebrowning commented on June 28, 2024

I cant seem to recreate, so going to close this issue. When / if I figure out what's importing os, ill let this thread know.

from swift-log.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.