क्या NSLog (@ "% s", __PRETTY_FUNCTION__) के लिए एक स्विफ्ट विकल्प है


88

ऑब्जेक्टिव C में आप उस विधि को लॉग कर सकते हैं जिसे प्रयोग करके बुलाया जा रहा है:

NSLog(@"%s", __PRETTY_FUNCTION__)

आमतौर पर इसका उपयोग लॉगिंग मैक्रो से किया जाता है।

हालाँकि स्विफ्ट मैक्रो का समर्थन नहीं करता है (मुझे लगता है) मैं अभी भी एक सामान्य लॉग स्टेटमेंट का उपयोग करना चाहूंगा जिसमें उस फ़ंक्शन का नाम शामिल है जिसे कॉल किया गया था। क्या स्विफ्ट में यह संभव है?

अद्यतन: मैं अब लॉगिंग के लिए इस वैश्विक फ़ंक्शन का उपयोग करता हूं जो यहां पाया जा सकता है: https://github.com/evermeer/Stuff#print और जिसे आप उपयोग करके इंस्टॉल कर सकते हैं:

pod 'Stuff/Print'

यहाँ कोड है:

public class Stuff {

    public enum logLevel: Int {
        case info = 1
        case debug = 2
        case warn = 3
        case error = 4
        case fatal = 5
        case none = 6

        public func description() -> String {
            switch self {
            case .info:
                return "❓"
            case .debug:
                return "✳️"
            case .warn:
                return "⚠️"
            case .error:
                return "🚫"
            case .fatal:
                return "🆘"
            case .none:
                return ""
            }
        }
    }

    public static var minimumLogLevel: logLevel = .info

    public static func print<T>(_ object: T, _ level: logLevel = .debug, filename: String = #file, line: Int = #line, funcname: String = #function) {
        if level.rawValue >= Stuff.minimumLogLevel.rawValue {
            let dateFormatter = DateFormatter()
            dateFormatter.dateFormat = "MM/dd/yyyy HH:mm:ss:SSS"
            let process = ProcessInfo.processInfo
            let threadId = "?"
            let file = URL(string: filename)?.lastPathComponent ?? ""
            Swift.print("\n\(level.description()) .\(level) ⏱ \(dateFormatter.string(from: Foundation.Date())) 📱 \(process.processName) [\(process.processIdentifier):\(threadId)] 📂 \(file)(\(line)) ⚙️ \(funcname) ➡️\r\t\(object)")
        }
    }
}

जिसका उपयोग आप इस तरह कर सकते हैं:

Stuff.print("Just as the standard print but now with detailed information")
Stuff.print("Now it's a warning", .warn)
Stuff.print("Or even an error", .error)

Stuff.minimumLogLevel = .error
Stuff.print("Now you won't see normal log output")
Stuff.print("Only errors are shown", .error)

Stuff.minimumLogLevel = .none
Stuff.print("Or if it's disabled you won't see any log", .error)    

जिसके परिणामस्वरूप होगा:

✳️ .debug ⏱ 02/13/2017 09:52:51:852 📱 xctest [18960:?] 📂 PrintStuffTests.swift(15) ⚙️ testExample() ➡️
    Just as the standard print but now with detailed information

⚠️ .warn ⏱ 02/13/2017 09:52:51:855 📱 xctest [18960:?] 📂 PrintStuffTests.swift(16) ⚙️ testExample() ➡️
    Now it's a warning

🚫 .error ⏱ 02/13/2017 09:52:51:855 📱 xctest [18960:?] 📂 PrintStuffTests.swift(17) ⚙️ testExample() ➡️
    Or even an error

🚫 .error ⏱ 02/13/2017 09:52:51:855 📱 xctest [18960:?] 📂 PrintStuffTests.swift(21) ⚙️ testExample() ➡️
    Only errors are shown

1
मैं उपयोग करता हूंNSLog("Running %@ : %@",NSStringFromClass(self.dynamicType),__FUNCTION__)
मैस्टर


1
मुझे लगता है कि आपकी लॉगिंग शैली "सुंदर फ़ंक्शन" की परिभाषा होनी चाहिए। साझा करने के लिए धन्यवाद।
हुआथैम

जवाबों:


101

स्विफ्ट है #file, #function, #line और #column। से स्विफ्ट प्रोग्रामिंग भाषा :

#file - स्ट्रिंग - उस फ़ाइल का नाम जिसमें यह दिखाई देता है।

#line - इंट - वह लाइन नंबर जिस पर यह दिखाई देता है।

#column - इंट - वह कॉलम संख्या जिसमें यह शुरू होता है।

#function - स्ट्रिंग - घोषणा का नाम जिसमें यह प्रकट होता है।


11
अच्छी तरह से यकीन है - उन सभी सी से आगे। लेकिन इस बारे में सवाल का जवाब नहीं दिया __PRETTY_FUNCTION__, जो आसानी से दिए गए विकल्पों में से नहीं बनाया गया है। (वहाँ एक है __CLASS__? यदि ऐसा है, तो वह मदद करेगा।)
ओली

10
स्विफ्ट 2.2 में # फंक्शन, # फील और अन्य का उपयोग करना चाहिए जैसा कि यहां दिखाया गया है: stackoverflow.com/a/35991392/1151916
रामिस

70

स्विफ्ट 2.2 से शुरू होकर हमें इसका उपयोग करना चाहिए:

  • # फ़ाइल (स्ट्रिंग) उस फ़ाइल का नाम जिसमें वह दिखाई देती है।
  • # लाइन (इंट) वह पंक्ति संख्या जिस पर यह दिखाई देता है।
  • # कॉलम (इंट) वह कॉलम संख्या जिसमें यह शुरू होता है।
  • # फंक्शन (स्ट्रिंग) उस घोषणा का नाम जिसमें यह प्रकट होता है।

से स्विफ्ट प्रोग्रामिंग लैंग्वेज (स्विफ्ट 3.1) पेज 894 पर।

func specialLiterals() {
    print("#file literal from file: \(#file)")
    print("#function literal from function: \(#function)")
    print("#line: \(#line) -> #column: \(#column)")
}
// Output:
// #file literal from file: My.playground
// #function literal from function: specialLiterals()
// #line: 10 -> #column: 42

1
इसे वर्तमान में सही उत्तर के रूप में चिह्नित किया जाना चाहिए।
डैनी ब्रावो

18

स्विफ्ट 4
यहां मेरा दृष्टिकोण है:

func pretty_function(_ file: String = #file, function: String = #function, line: Int = #line) {

    let fileString: NSString = NSString(string: file)

    if Thread.isMainThread {
        print("file:\(fileString.lastPathComponent) function:\(function) line:\(line) [M]")
    } else {
        print("file:\(fileString.lastPathComponent) function:\(function) line:\(line) [T]")
    }
}

इसे एक ग्लोबल फंक्शन बनाएं और सिर्फ कॉल करें

pretty_function()

बोनस: आप देखेंगे कि थ्रेड को निष्पादित किया गया है, पृष्ठभूमि के धागे के लिए [T] और मुख्य धागे के लिए [M]।


स्ट्रिंग से NSString में फ़ाइल की घोषणा को बदलने की आवश्यकता है। lastPathComponent स्ट्रिंग पर उपलब्ध नहीं है।
प्रिमुलेविस

1
बेहतरीन दोस्त। स्विफ्ट> 2.1 के लिए छोटे बदलाव: "प्रिंटलाइन" का नाम बदलकर "प्रिंट" कर दिया गया है। प्रिंट ("फ़ाइल: (file.debugDescription) फ़ंक्शन: (फ़ंक्शन) लाइन: (लाइन)")
जॉन डो

कूल, अच्छा है कि यह काम करता है। किसी भी तरह से कक्षा / ऑब्जेक्ट को पास करने में सक्षम होना बहुत अच्छा होगा (एक विकल्प एक स्पष्ट स्व तर्क का उपयोग करना है)। धन्यवाद।
तिब्बत का समुद्री तट

आपके दृष्टिकोण की समस्याएं: - यह फ़ंक्शन थ्रेड-सुरक्षित नहीं है। यदि आप इसे एक ही बार में विभिन्न थ्रेड्स से बुलाते हैं, तो कुछ बुरे आश्चर्य के लिए तैयार रहें - वैश्विक कार्यों का उपयोग करना बुरा अभ्यास है
Karoly Nyisztor

9

XCode बीटा 6 के रूप में, आप reflect(self).summaryकक्षा का नाम पाने के लिए और का उपयोग कर सकते हैं__FUNCTION__ पाने के लिए और फ़ंक्शन नाम प्राप्त , लेकिन अभी चीजें थोड़ी गड़बड़ हैं। उम्मीद है, वे बेहतर समाधान के साथ आएंगे। जब तक हम बीटा से बाहर नहीं होंगे तब तक #define का उपयोग करना सार्थक हो सकता है।

यह कोड:

NSLog("[%@ %@]", reflect(self).summary, __FUNCTION__)

परिणाम इस तरह देता है:

2014-08-24 08:46:26.606 SwiftLessons[427:16981938] [C12SwiftLessons24HelloWorldViewController (has 2 children) goodbyeActiongoodbyeAction]

संपादित करें: यह अधिक कोड है, लेकिन मुझे अपनी ज़रूरत के करीब मिल गया, जो मुझे लगता है कि आप जो चाहते थे।

func intFromString(str: String) -> Int
{
    var result = 0;
    for chr in str.unicodeScalars
    {
        if (chr.isDigit())
        {
            let value = chr - "0";
            result *= 10;
            result += value;
        }
        else
        {
            break;
        }
    }

    return result;
}


@IBAction func flowAction(AnyObject)
{
    let cname = _stdlib_getTypeName(self)
    var parse = cname.substringFromIndex(1)                                 // strip off the "C"
    var count = self.intFromString(parse)
    var countStr = String(format: "%d", count)                              // get the number at the beginning
    parse = parse.substringFromIndex(countStr.lengthOfBytesUsingEncoding(NSUTF8StringEncoding))
    let appName = parse.substringToIndex(count)                             // pull the app name

    parse = parse.substringFromIndex(count);                                // now get the class name
    count = self.intFromString(parse)
    countStr = String(format: "%d", count)
    parse = parse.substringFromIndex(countStr.lengthOfBytesUsingEncoding(NSUTF8StringEncoding))
    let className = parse.substringToIndex(count)
    NSLog("app: %@ class: %@ func: %@", appName, className, __FUNCTION__)
}

यह इस तरह उत्पादन देता है:

2014-08-24 09:52:12.159 SwiftLessons[1397:17145716] app: SwiftLessons class: ViewController func: flowAction

8

मैं एक वैश्विक लॉग फ़ंक्शन को परिभाषित करना पसंद करता हूं:

[स्विफ्ट 3.1]

func ZYLog(_ object: Any?, filename: String = #file, line: Int = #line, funcname: String = #function) {
    #if DEBUG
    print("****\(Date()) \(filename)(\(line)) \(funcname):\r\(object ?? "nil")\n")
    #endif
}

[स्विफ्ट 3.0]

func ZYLog<T>(_ object: T?, filename: String = #file, line: Int = #line, funcname: String = #function) {
    #if DEBUG
    print("****\(Date()) \(filename)(\(line)) \(funcname):\r\(object)\n")
    #endif
}

[स्विफ्ट 2.0]

func ZYLog<T>(object: T, filename: String = __FILE__, line: Int = __LINE__, funcname: String = __FUNCTION__) {
    println("****\(filename.lastPathComponent)(\(line)) \(funcname):\r\(object)\n")
}

आउटपुट कुछ इस तरह है:

****ZYHttpSessionManager.swift(78) POST(_:parameters:success:failure:):
[POST] user/login, {
    "auth_key" = xxx;
    "auth_type" = 0;
    pwd = xxx;
    user = "xxx";
}

****PointViewController.swift(162) loadData():
review/list [limit: 30, skip: 0]

****ZYHttpSessionManager.swift(66) GET(_:parameters:success:failure:):
[GET] review/list, {
    "auth_key" = xxx;
    uuid = "xxx";
}

आपको वास्तव में यहां एक सामान्य फ़ंक्शन की आवश्यकता नहीं है, क्योंकि objectपैरामीटर को Anyइसके बजाय घोषित किया जा सकता है T
werediver

5

यहाँ एक अद्यतन स्विफ्ट 2 उत्तर है।

func LogW(msg:String, function: String = __FUNCTION__, file: String = __FILE__, line: Int = __LINE__){
    print("[WARNING]\(makeTag(function, file: file, line: line)) : \(msg)")
}

private func makeTag(function: String, file: String, line: Int) -> String{
    let url = NSURL(fileURLWithPath: file)
    let className:String! = url.lastPathComponent == nil ? file: url.lastPathComponent!
    return "\(className) \(function)[\(line)]"
}

उपयोग का उदाहरण:

LogW("Socket connection error: \(error)")

1
यह शानदार है। लेकिन तब फिर से .. LogW को प्रिंट (), पैरामीटर्स द्वारा अलग किए गए (कॉमा द्वारा अलग किए गए) के समान उपयोग नहीं किया जा सकता है ..
गुंटिस ट्रेन्डैंड्स

"लॉग (प्रिंट के रूप में) (मापदंडों के साथ, कॉमा द्वारा अलग किए गए) का उपयोग नहीं किया जा सकता है" मैं इस समर्थन को जोड़ने के लिए सोच रहा था लेकिन मैंने पाया कि मुझे इसकी आवश्यकता नहीं थी। "लॉगडब्ल्यू (" सॉकेट कनेक्शन त्रुटि:) (त्रुटि) अन्य जानकारी : (otherInfo) ")"
डैनियल रेयान

1
सच। अच्छी तरह से मैं इधर-उधर हो गया और केवल एक और समाधान मैंने पाया - स्टेटमेंट को होल्ड करने के लिए अतिरिक्त () का उपयोग करके, इसे प्रिंट करने के लिए () जितना संभव हो सके। इस एक github.com/GuntisTreulands/ColorLogger-Swift को बनाने के लिए अपने उत्तर का उपयोग करें , बहुत बहुत धन्यवाद! :)
गुंटिस ट्रेन्डलैंड

बहुत उपयोगी! स्विफ्ट 2.2 के रूप में,__FUNCTION__ becomes #function, __FILE__ becomes #file, and __LINE__ becomes #line.
कार्ल स्मिथ

हमें नए मूल्यों से परेशानी थी। हम अपने कोड आधार को अपडेट करने तक स्विफ्ट 3 तक इंतजार करेंगे।
डैनियल रयान

0

या इसके साथ मामूली कार्य संशोधन:

func logFunctionName(file:String = __FILE__, fnc:String = __FUNCTION__, line:(Int)=__LINE__) {
    var className = file.lastPathComponent.componentsSeparatedByString(".")
    println("\(className[0]):\(fnc):\(line)")

}

/ * एक निष्पादन ट्रेस उत्पन्न करेगा जैसे: AppDelegate: application (_: didFinishLaunchingWithOptions :): 18 उत्पाद: init (प्रकार: नाम: वर्ष: मूल्य :): 34 FirstViewController: viewDelLoad (): 15 AppDelegate: applicationDidBecomeActive: 62 * /


0

मैं उपयोग करता हूं, यह एक स्विफ्ट फ़ाइल में आवश्यक है, अन्य सभी फाइलें इसे (एक वैश्विक कार्य के रूप में) उठाएंगी। जब आप एप्लिकेशन को जारी करना चाहते हैं तो केवल टिप्पणी करें।

import UIKit

func logFunctionName(file:NSString = __FILE__, fnc:String = __FUNCTION__){  
    println("\(file.lastPathComponent):\(fnc)")
}

0

स्विफ्ट 3.0

public func LogFunction<T>(object: T, filename: String = #file, line: Int = #line, funcname: String = #function) {
    let dateFormatter = DateFormatter()
    dateFormatter.dateFormat = "MM/dd/yyyy HH:mm:ss:SSS"
    let process = ProcessInfo.processInfo()
    let threadId = "?"
    print("\(dateFormatter.string(from:Date())) \(process.processName) [\(process.processIdentifier):\(threadId)] \(filename)(\(line)) \(funcname)::: \(object)")
}

0

स्विफ्ट 3.x +

यदि आप संपूर्ण फ़ाइल नाम नहीं चाहते हैं, तो उसके लिए यहां एक त्वरित सुधार है।

func trace(fileName:String = #file, lineNumber:Int = #line, functionName:String = #function) -> Void {
    print("filename: \(fileName.components(separatedBy: "/").last!) function: \(functionName) line: #\(lineNumber)")
}

filename: ViewController.swift function: viewDidLoad() line: #42

0

फ़ंक्शन कॉल लॉग करने का दूसरा तरीका:

NSLog("\(type(of:self)): %@", #function)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.