Veja neste guia como personalizar seus relatórios de erros usando o SDK do Firebase Crashlytics. Por padrão, o Crashlytics coleta automaticamente relatórios de erros para todos os usuários do seu app. Se quiser, desative os relatórios de falhas automáticos e ative os relatórios de permissão para os usuários. O Crashlytics oferece quatro mecanismos de geração de registros prontos para uso: chaves personalizadas, registros personalizados, identificadores de usuários e exceções capturadas.
Adicionar chaves personalizadas
As chaves personalizadas ajudam você a chegar ao estado específico do seu aplicativo que está gerando uma falha. É possível associar pares de chave-valor arbitrários aos seus relatórios de erros e usar as chaves personalizadas para pesquisar e filtrar relatórios de erros no Console do Firebase.
- No painel do Crashlytics, é possível pesquisar problemas que correspondam a uma chave personalizada.
- Ao analisar um problema específico no console, você pode ver as chaves personalizadas associadas a cada evento (subguia Chaves) e até mesmo filtrar os eventos por chaves personalizadas (Filtro, na parte de cima da página).
Use o método setCustomValue
para definir pares de chave-valor. Exemplo:
Swift
// Set int_key to 100. Crashlytics.crashlytics().setCustomValue(100, forKey: "int_key") // Set str_key to "hello". Crashlytics.crashlytics().setCustomValue("hello", forKey: "str_key")
Objective-C
Ao definir números inteiros, booleanos ou flutuantes, defina o valor como @(value)
.
// Set int_key to 100. [[FIRCrashlytics crashlytics] setCustomValue:@(100) forKey:@"int_key"]; // Set str_key to "hello". [[FIRCrashlytics crashlytics] setCustomValue:@"hello" forKey:@"str_key"];
Para modificar o valor de uma chave atual, chame a chave e defina-a com um valor diferente. Exemplo:
Swift
Crashlytics.crashlytics().setCustomValue(100, forKey: "int_key") // Set int_key to 50 from 100. Crashlytics.crashlytics().setCustomValue(50, forKey: "int_key")
Objective-C
[[FIRCrashlytics crashlytics] setCustomValue:@(100) forKey:@"int_key"]; // Set int_key to 50 from 100. [[FIRCrashlytics crashlytics] setCustomValue:@(50) forKey:@"int_key"];
Adicione pares de chave-valor em massa usando o método setCustomKeysAndValues
com um
NSDictionary como o único parâmetro:
Swift
let keysAndValues = [ "string key" : "string value", "string key 2" : "string value 2", "boolean key" : true, "boolean key 2" : false, "float key" : 1.01, "float key 2" : 2.02 ] as [String : Any] Crashlytics.crashlytics().setCustomKeysAndValues(keysAndValues)
Objective-C
NSDictionary *keysAndValues = @{@"string key" : @"string value", @"string key 2" : @"string value 2", @"boolean key" : @(YES), @"boolean key 2" : @(NO), @"float key" : @(1.01), @"float key 2" : @(2.02)}; [[FIRCrashlytics crashlytics] setCustomKeysAndValues: keysAndValues];
Adicionar mensagens de registro personalizadas
Para dar mais contexto aos eventos que geram uma falha, adicione registros personalizados do Crashlytics ao seu app. O Crashlytics associa os registros aos dados de falhas e os exibe na página do Crashlytics do Console do Firebase, na guia Registros.
Swift
Use log()
ou log(format:, arguments:)
para ajudar a identificar problemas. Se você
quiser receber uma saída de registro útil com mensagens, o objeto que você passar para
log()
precisará estar em conformidade com a propriedade
CustomStringConvertible
. log()
retorna a propriedade de descrição definida para
o objeto. Exemplo:
Crashlytics.crashlytics().log("Higgs-Boson detected! Bailing out…, \(attributesDict)")
.log(format:, arguments:)
formata valores retornados da chamada
getVaList()
. Exemplo:
Crashlytics.crashlytics().log(format: "%@, %@", arguments: getVaList(["Higgs-Boson detected! Bailing out…", attributesDict]))
Para mais detalhes sobre como usar log()
ou log(format:, arguments:)
,
consulte a documentação de referência do Crashlytics.
Objective-C
Use log
ou logWithFormat
para ajudar a identificar problemas. Se você
quiser receber uma saída de registro útil com mensagens, o objeto que você passar
para qualquer método precisará modificar a propriedade da instância description
.
Exemplo:
[[FIRCrashlytics crashlytics] log:@"Simple string message"]; [[FIRCrashlytics crashlytics] logWithFormat:@"Higgs-Boson detected! Bailing out... %@", attributesDict]; [[FIRCrashlytics crashlytics] logWithFormat:@"Logging a variable argument list %@" arguments:va_list_arg];
Para mais detalhes sobre como usar log
e logWithFormat
, consulte a
documentação de referência do Crashlytics.
Definir identificadores de usuários
Para diagnosticar um problema, muitas vezes é útil saber quais usuários observaram uma determinada falha. O Crashlytics inclui uma maneira de identificar anonimamente os usuários nos relatórios de erros.
Para adicionar IDs de usuários aos seus relatórios, atribua a cada usuário um identificador exclusivo na forma de um número de ID, token ou valor de hash:
Swift
Crashlytics.crashlytics().setUserID("123456789")
Objective-C
[[FIRCrashlytics crashlytics] setUserID:@"123456789"];
Se você precisar apagar um identificador de usuário depois de configurá-lo, redefina o valor deixando uma string em branco. Limpar um identificador de usuário não remove os registros atuais do Crashlytics. Se você precisar excluir registros associados a um ID de usuário, entre em contato com o suporte do Firebase.
Reportar exceções não fatais
Além de reportar automaticamente as falhas do seu app, o Crashlytics permite registrar exceções não fatais e enviá-las para você na próxima vez que o app for iniciado.
Para registrar exceções não fatais, grave objetos NSError
com o
método recordError
. recordError
captura a pilha de chamadas da linha de execução ao chamar
[NSThread callStackReturnAddresses]
.
Swift
Crashlytics.crashlytics().record(error: error)
Objective-C
[[FIRCrashlytics crashlytics] recordError:error];
Ao usar o método recordError
, é importante entender a estrutura NSError
e como o Crashlytics usa os dados para agrupar falhas. O uso incorreto
do método recordError
pode causar um comportamento imprevisível e fazer com que o
Crashlytics limite os relatórios de erros registrados para seu app.
Um objeto NSError
tem três argumentos:
domain: String
code: Int
userInfo: [AnyHashable : Any]? = nil
Ao contrário das falhas fatais, que são agrupadas usando a análise de stack trace, os erros registrados
são agrupados por domain
e code
. Esta é uma distinção importante
entre falhas fatais e erros registrados. Exemplo:
Swift
let userInfo = [ NSLocalizedDescriptionKey: NSLocalizedString("The request failed.", comment: ""), NSLocalizedFailureReasonErrorKey: NSLocalizedString("The response returned a 404.", comment: ""), NSLocalizedRecoverySuggestionErrorKey: NSLocalizedString("Does this page exist?", comment: ""), "ProductID": "123456", "View": "MainView" ] let error = NSError.init(domain: NSCocoaErrorDomain, code: -1001, userInfo: userInfo)
Objective-C
NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: NSLocalizedString(@"The request failed.", nil), NSLocalizedFailureReasonErrorKey: NSLocalizedString(@"The response returned a 404.", nil), NSLocalizedRecoverySuggestionErrorKey: NSLocalizedString(@"Does this page exist?", nil), @"ProductID": @"123456", @"View": @"MainView", }; NSError *error = [NSError errorWithDomain:NSCocoaErrorDomain code:-1001 userInfo:userInfo];
Quando você registra o erro acima, ele cria um novo problema agrupado por
NSSomeErrorDomain
e -1001
. Outros erros registrados que usam os mesmos
valores de domínio e código são agrupados no mesmo problema. Os dados contidos no objeto
userInfo
são convertidos em pares de chave-valor e exibidos na seção de chaves/registros
em um problema individual.
Registros e chaves personalizadas
Assim como os relatórios de erros, é possível incorporar registros e chaves personalizadas para dar mais contexto
ao NSError
. No entanto, há uma diferença entre registros anexados a
falhas e erros registrados. Quando ocorre uma falha e o app é reiniciado, os
registros do Crashlytics recuperados do disco são os que foram gravados até
o momento da falha. Quando você registra um NSError
, o app não é encerrado
imediatamente. Como o Crashlytics só envia o relatório de erros registrado na
próxima inicialização do app e precisa limitar a quantidade de espaço alocado para os registros no disco,
é possível registrar o suficiente depois que um NSError
é gravado para que todos os registros relevantes
sejam substituídos no momento em que o Crashlytics enviar o relatório do
dispositivo. Lembre-se desse equilíbrio ao registrar NSErrors
e usar registros
e chaves personalizadas no seu app.
Considerações sobre desempenho
Lembre-se de que registrar um NSError
pode ser bastante caro. No momento em que você
faz a chamada, o Crashlytics captura a pilha de chamadas da linha de execução atual usando um
processo chamado desenrolamento de pilha. Esse processo pode consumir muita CPU e E/S,
principalmente em arquiteturas que suportam o desenrolamento DWARF (arm64 e x86).
Quando o desenrolamento estiver finalizado, as informações serão gravadas em disco de maneira síncrona.
Isso evita a perda de dados se a próxima linha falhar.
Embora seja seguro chamar essa API em uma linha de execução em segundo plano, lembre-se de que o envio dessa chamada para outra fila perde o contexto do rastreamento de pilha atual.
E as NSExceptions?
O Crashlytics não oferece um recurso para registrar e gravar instâncias NSException
diretamente. De modo geral, as APIs Cocoa e Cocoa Touch não
são seguras contra exceções. Isso significa que o uso de @catch
pode ter efeitos indesejados
muito graves no seu processo, mesmo quando usado com muito cuidado. Nunca use
instruções @catch
no seu código. Consulte a
documentação da Apple (em inglês) sobre o assunto.
Personalizar stack traces
Se o app for executado em um ambiente não nativo, como C ++ ou Unity, será possível usar a API Exception Model para reportar metadados de falha no formato de exceção nativa do app. As exceções reportadas são consideradas não fatais.
Swift
var ex = ExceptionModel(name:"FooException", reason:"There was a foo.") ex.stackTrace = [ StackFrame(symbol:"makeError", file:"handler.js", line:495), StackFrame(symbol:"then", file:"routes.js", line:102), StackFrame(symbol:"main", file:"app.js", line:12), ] crashlytics.record(exceptionModel:ex)
Objective-C
FIRExceptionModel *model = [FIRExceptionModel exceptionModelWithName:@"FooException" reason:@"There was a foo."]; model.stackTrace = @[ [FIRStackFrame stackFrameWithSymbol:@"makeError" file:@"handler.js" line:495], [FIRStackFrame stackFrameWithSymbol:@"then" file:@"routes.js" line:102], [FIRStackFrame stackFrameWithSymbol:@"main" file:@"app.js" line:12], ]; [[FIRCrashlytics crashlytics] recordExceptionModel:model];
Frames de pilha personalizados também podem ser inicializados apenas com endereços:
Swift
var ex = ExceptionModel.init(name:"FooException", reason:"There was a foo.") ex.stackTrace = [ StackFrame(address:0xfa12123), StackFrame(address:12412412), StackFrame(address:194129124), ] crashlytics.record(exceptionModel:ex)
Objective-C
FIRExceptionModel *model = [FIRExceptionModel exceptionModelWithName:@"FooException" reason:@"There was a foo."]; model.stackTrace = @[ [FIRStackFrame stackFrameWithAddress:0xfa12123], [FIRStackFrame stackFrameWithAddress:12412412], [FIRStackFrame stackFrameWithAddress:194129124], ]; [[FIRCrashlytics crashlytics] recordExceptionModel:model];
Ative a permissão para geração de relatórios
Por padrão, o Crashlytics coleta automaticamente relatórios de erros para todos os usuários do seu app. Caso queira dar aos usuários mais controle sobre os dados enviados, é possível ativar a geração de relatórios. Para fazer isso, basta desativar a geração automática de relatórios e enviar dados ao Crashlytics somente quando você escolher no seu código:
Para desativar a coleta automática, adicione uma nova chave ao arquivo
Info.plist
:- Chave:
FirebaseCrashlyticsCollectionEnabled
- Valor:
false
- Chave:
Para ativar a coleta nos usuários selecionados, chame a modificação da coleta de dados do Crashlytics no ambiente de execução. O valor de modificação continua entre os lançamentos do seu app. Assim, o Crashlytics pode coletar relatórios automaticamente.
Para desativar o relatório automático de falhas, transmita
false
como o valor de modificação. Quando definido comofalse
, o novo valor não se aplica até a próxima execução do app.Swift
Crashlytics.crashlytics().setCrashlyticsCollectionEnabled(true)
Objective-C
[[FIRCrashlytics crashlytics] setCrashlyticsCollectionEnabled:YES];
Gerenciar dados do Crash Insights
Com o Crash Insights, você soluciona problemas quando compara stack traces anônimos a traces de outros aplicativos do Firebase. Você receberá um aviso se o problema fizer parte de uma tendência maior. Para muitos problemas, o Crash Insights também oferece recursos para ajudar a depurar a falha.
Ele usa dados de falhas agregados para identificar tendências de estabilidade comuns. Caso prefira não compartilhar os dados do app, é possível desativar o Crash Insights no menu com o mesmo nome na parte de cima da lista de problemas do Crashlytics no Console do Firebase.