Подтвердить что ты не робот

Как использовать запись Crashlytics в Swift?

В этой статье описывается использование журнала Crashlytics в objective-c. Тем не менее, после прохождения шагов установки для правильной ссылки на Crashlytics и Fabric в мой проект, похоже, у меня нет доступа к этому методу.

Глядя на файл Crashlytics.h, я вижу, что он определен с использованием флагов компилятора:

#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

Этот блок только что обертывает функции CLSNLog и CLSLog в зависимости от флага компилятора.

Итак, думая, что я просто пойду прямо к источнику, я попытался ссылаться на CLSLog напрямую из быстрого файла. Еще не повезло:

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)
}

Последние две строки в функции Log вызывают ошибку, Use of unresolved identifier. Отчеты Crashlytics crash работают очень хорошо, за исключением функции ведения журнала. Согласно этой, была реализована поддержка ведения журнала для Swift.

Что касается версий, я использую последнюю версию Fabric/Crashlytics (декабрьская версия на момент публикации).

(Интересно отметить, что я вижу/использую CLSLogv()...)

Кто-нибудь знает правильный способ включить CLS_LOG для использования в проекте Swift?

4b9b3361

Ответ 1

Вам нужно создать промежуточный мост следующим образом:

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"

Затем вы можете просто добавить это к вашей функции Log:

func Log(message: String) {
    CrashlyticsBridge.log(message)
}

Это даст вам журнал Crashlytics и NSLogging во время отладки.

Ответ 2

Майк из Crashlytics здесь.

Чтобы использовать пользовательский журнал в Swift, используйте CLSLogv или CLSNSLogv. Вам нужно создать массив, а затем вызвать функцию getVaList в этом массиве.

Вот фрагмент:

CLSLogv("Log something %d %d %@", getVaList([1, 2, "three"]))

Для CLSNSLogv:

CLSNSLogv("hello %@", getVaList(["goodbye"]))

Ответ 3

Мне нужно что-то похожее на CLS_LOG() в Swift, которое распечатало контекстуальную информацию о местонахождении вызова. Обычно это было бы невозможно без предпроцессорных директив, но я узнал, как скопировать это поведение довольно близко в Swift здесь: https://developer.apple.com/swift/blog/?id=15

Идентификаторы, которые нам нужны (#file, #function, #line), отображают информацию о вызывающем абоненте, если вы задали их как значения по умолчанию в списке аргументов.

Примечание. Если вы регистрируете ошибки, которые могут иметь в них символы %, такие как строки сетевых запросов, это может привести к сбою. Сначала вам нужно присоединиться к строке (например, let string = "\(filename).\(function) line \(line) $ \(message)")

версия Swift 3 (обратите внимание: это глобальная функция, поэтому она должна быть размещена вне любого определения структуры или класса):

/// 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:

// 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 $

И вот суть с некоторой дополнительной информацией и фактическим файлом, в который я помещаю этот код: https://gist.github.com/DimaVartanian/a8aa73ba814a61f749c0

Как вы можете видеть, он довольно близок к исходному макросу и отличается только тем, что вы не можете видеть, вызываете ли вы метод класса или метод экземпляра, и что вам нужно включить список аргументов формата, заключенный в массив. Оба являются ограничениями, я считаю, что сейчас нет никакого способа, но довольно незначительный. Вы также должны убедиться, что DEBUG определен в ваших флагах компилятора Swift. Он не переносится с ваших обычных флагов автоматически.

Ответ 4

Вот моя адаптированная версия (от Димы). Мне не нужны аргументы, так как вы можете сделать все форматирование в строке Swift, которую вы передаете.

func DebugLog(_ message: String,
              file: StaticString = #file,
              function: StaticString = #function,
              line: Int = #line)
{
    let output: String
    if let filename = URL(string: String(describing: file))?.lastPathComponent.components(separatedBy: ".").first
    {
        output = "\(filename).\(function) line \(line) $ \(message)"
    }
    else
    {
        output = "\(file).\(function) line \(line) $ \(message)"
    }

    #if DEBUG
        CLSNSLogv("%@", getVaList([output]))
    #else
        CLSLogv("%@", getVaList([output]))
    #endif
}

И вы будете использовать его следующим образом:

DebugLog("this is a log message")
DebugLog("this is a log message \(param1) \(param2)")

EDIT: обновлено до Swift 3.1

Ответ 5

Совместимость с Swift 3

Вам нужно настроить флаг компилятора для использования препроцессора Swift - перейдите в раздел Swift Compiler - Custom Flags Build Settings, чтобы установить флаг -D DEBUG

введите описание изображения здесь

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 совместимая версия для сообщения журнала в 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

Любой, кто хочет зарегистрировать ошибку usin Crashlytics, может использовать приведенный ниже код и его работу отлично для меня:)

Crashlytics.sharedInstance().recordError(error)

ошибка - это объект NSERROR, который содержит ошибку, возникшую при некотором действии