可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
This article describes how to use Crashlytics logging in objective-c. However, after going throught the installation steps for propertly referencing Crashlytics and Fabric into my project, I don't seem to have access to that method.
Looking at the Crashlytics.h file, I can see it defined using compiler flags:
#ifdef DEBUG
#define CLS_LOG(__FORMAT__, ...) CLSNSLog((@"%s line %d $ " __FORMAT__), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
#else
#define CLS_LOG(__FORMAT__, ...) CLSLog((@"%s line %d $ " __FORMAT__), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
#endif
This block just appears to wrap the CLSNLog
and the CLSLog
functions depending on the compiler flag.
So, thinking I'd just go straight to the source, I tried to reference CLSLog directly from a swift file. Still no luck:
My-Bridging-Header.h:
#import <Crashlytics/Crashlytics.h>
Log.swift:
import Foundation
import Fabric
import Crashlytics
func Log(message: String) {
NSLog("%@", message)
CLS_LOG("%@", message)
CLSLog("%@", message)
}
The last two lines in the Log function throw the error, Use of unresolved identifier
. Crashlytics crash reporting works just fine, except for the logging feature. According to this article, logging support for Swift has been implemented.
As far as versions go, I'm running the latest version of Fabric/Crashlytics (December release, at the time of this post).
(Interesting note, I can see/use CLSLogv()
...)
Does anyone know the correct way to incorporate CLS_LOG
for use in a Swift project?
回答1:
You have to create an intermediary bridge like this:
CrashlyticsBridge.h:
#import <Foundation/Foundation.h>
@interface CrashlyticsBridge : NSObject
+ (void)log:(NSString *)message;
@end
CrashlyticsBridge.m
#import "CrashlyticsBridge.h"
#import <Crashlytics/Crashlytics.h>
@implementation CrashlyticsBridge
+ (void)log:(NSString *)message {
CLS_LOG(@"%@", message);
}
@end
My-Bridging-Header.h:
#import "CrashlyticsBridge.h"
Then, you can simply add that to your Log
function:
func Log(message: String) {
CrashlyticsBridge.log(message)
}
This will give you the Crashlytics logging and NSLogging while you are debugging.
回答2:
Mike from Crashlytics here.
To use custom logging in Swift, just use CLSLogv or CLSNSLogv. You need to make an array and then call getVaList function on that array.
Here's a snippet:
CLSLogv("Log something %d %d %@", getVaList([1, 2, "three"]))
For CLSNSLogv:
CLSNSLogv("hello %@", getVaList(["goodbye"]))
回答3:
Here is my version adapted from Dima's answer. I have no need of the arguments, since you can do all the formatting within the Swift string that you pass.
func DebugLog(_ message: String, file: StaticString = #file, function: StaticString = #function, line: Int = #line) {
let output: String
if let filename = URL(fileURLWithPath: file.description).lastPathComponent.components(separatedBy: ".").first {
output = "\(filename).\(function) line \(line) $ \(message)"
} else {
output = "\(file).\(function) line \(line) $ \(message)"
}
#if targetEnvironment(simulator)
NSLogv("%@", getVaList([output]))
#elseif DEBUG
CLSNSLogv("%@", getVaList([output]))
#else
CLSLogv("%@", getVaList([output]))
#endif
}
And you would use it like this:
DebugLog("this is a log message")
DebugLog("this is a log message \(param1) \(param2)")
EDIT: Updated to Swift 3.1
回答4:
I needed something similar to CLS_LOG()
in Swift that printed out contextual information about the location of the call. Normally this would not be possible without preprocessor directives but I found out how to replicate this behavior pretty closely in Swift here:
https://developer.apple.com/swift/blog/?id=15
The identifiers we need (#file, #function, #line
) show information about the caller if you set them as default values in an argument list.
Note: If you are logging errors that may have %
symbols in them, such as network query strings, this may crash. You'll need to join the string first (e.g. let string = "\(filename).\(function) line \(line) $ \(message)"
)
Swift 3 version (note: this is a global function, so it should be placed outside of any struct or class definition):
/// Usage:
///
/// CLS.log("message!")
/// CLS.log("message with parameter 1: %@ and 2: %@", ["First", "Second"])
///
func CLS_LOG_SWIFT(format: String = "", _ args: [CVarArg] = [], file: String = #file, function: String = #function, line: Int = #line)
{
let filename = URL(string: file)?.lastPathComponent.components(separatedBy: ".").first
#if DEBUG
CLSNSLogv("\(filename).\(function) line \(line) $ \(format)", getVaList(args))
#else
CLSLogv("\(filename).\(function) line \(line) $ \(format)", getVaList(args))
#endif
}
Swift 2 version:
// CLS_LOG_SWIFT()
// CLS_LOG_SWIFT("message!")
// CLS_LOG_SWIFT("message with parameter 1: %@ and 2: %@", ["First", "Second"])
func CLS_LOG_SWIFT(format: String = "",
_ args:[CVarArgType] = [],
file: String = __FILE__,
function: String = __FUNCTION__,
line: Int = __LINE__)
{
let filename = NSURL(string:file)?.lastPathComponent?.componentsSeparatedByString(".").first
#if DEBUG
CLSNSLogv("\(filename).\(function) line \(line) $ \(format)", getVaList(args))
#else
CLSLogv("\(filename).\(function) line \(line) $ \(format)", getVaList(args))
#endif
}
// CLS_LOG() output: -[ClassName methodName:] line 10 $
// CLS_LOG_SWIFT() output: ClassName.methodName line 10 $
And here is a gist with some more information and the actual file I put this code in: https://gist.github.com/DimaVartanian/a8aa73ba814a61f749c0
As you can see it is pretty close to the original macro and only differs in that you can't see if you are calling a class method or an instance method, and that you need to include your format argument list enclosed in an array. Both are limitations I believe there is no way around right now but pretty minor. You also need to make sure DEBUG is defined in your Swift compiler flags. It does not carry over from your regular flags automatically.
回答5:
Swift 3 compatible
You'll need to set up a compiler flag to use the Swift preprocessor - go to the Swift Compiler - Custom Flags
section of Build Settings
to set up a -D DEBUG
flag
func dLog(message: Any, filename: String = #file, function: String = #function, line: Int = #line) {
#if DEBUG
print("[\(filename.lastPathComponent):\(line)] \(function) - \(message)")
#else
CLSLogv("[\(filename.lastPathComponent):\(line)] \(function) - \(message)", getVaList([""]))
#endif
}
dLog(object)
回答6:
Swift 3 compatible version for log message in Crashlytics
func CLS_LOG_SWIFT(_ format: String = "", _ args: [CVarArg] = [], file: String = #file, function: String = #function, line: Int = #line) {
let formatString: String!
if let filename = file.components(separatedBy: "/").last?.components(separatedBy: ".").first {
formatString = "\(filename).\(function) line \(line) $ \(format)"
}else{
formatString = "\(file).\(function) line \(line) $ \(format)"
}
#if DEBUG
CLSNSLogv(formatString, getVaList(args))
#else
CLSLogv(formatString, getVaList(args))
#endif
}
回答7:
How about like this?
import Foundation
import Crashlytics
func CLSLog(_ format: String = "", _ args: CVarArg..., file: String = #file, function: String = #function, line: Int = #line) {
let formatString: String!
if let filename = file.components(separatedBy: "/").last?.components(separatedBy: ".").first {
formatString = "\(filename).\(function) line \(line) $ \(format)"
} else {
formatString = "\(file).\(function) line \(line) $ \(format)"
}
#if DEBUG
CLSNSLogv(formatString, getVaList(args))
#else
CLSLogv(formatString, getVaList(args))
#endif
}
No need for the array then, just list the variadic parameters
CLSLog("message")
CLSLog("message %@ %@", "one", "two")
回答8:
Any one who want to log error usin Crashlytics can use the below code and its working fine for me :)
Crashlytics.sharedInstance().recordError(error)
error is NSERROR object that holds the error that produced during some action