Comments (16)
Trying to create a project that reproduces this though.
from swift-log.
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.
@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.
@weissi Im personally not, but a dependency might be.
import FirebaseCrashlytics
import Logging
import UIKit
from swift-log.
@kylebrowning it will be fine if a dependency does unless they do @_exported import OSLog
/@_exported import os
from swift-log.
@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.
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.
@kylebrowning can you give me the whole set of import
s from the file that fails?
from swift-log.
For your error to happen that file must have (somehow) imported both OSLog
/os
and Logging
from swift-log.
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.
If I was importing both of those, wouldn't this also fail to compile on Xcode 11?
from swift-log.
@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.
@kylebrowning but maybe I'm missing something. Can you create a small Xcode project that reproduces this?
from swift-log.
@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.
❯ 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.
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)
- Toggle verbose or off HOT 1
- Crash when using error log / Incomplete LogHandler implementation HOT 2
- Infinite recursion between deprecated API's HOT 4
- MultiplexLogHandler to learn about metadata providers
- Add new Discord Logger to README HOT 2
- Make `StdioOutputStream` public HOT 1
- Supported way of accumulating metadata down the callstack HOT 9
- Logging function autoclosures aren't "rethrows" HOT 8
- Simplify logging `Error` types HOT 4
- Support advanced loghandler metadata use cases HOT 2
- Make StreamLogHandler initializers public
- How should I disclose using Swift Log in my iOS app?
- Unsupported runtime for visionOS HOT 1
- Fails to compile on Fedora 39 with Swift 5.8.1 (From repos) or official 5.9 binaries HOT 7
- PrivacyInfo Manifest HOT 2
- visionOS Compatibility HOT 1
- "Unsupported Runtime" when compiling for xrOS HOT 2
- Adding Error to log functions HOT 2
- CoW (copy-on-write) box the `Logger` components (for perf) HOT 2
- .string and .stringConvertable metadata value equality HOT 7
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from swift-log.