قم بتخصيص تقارير الأعطال الخاصة بـ Firebase Crashlytics

في لوحة معلومات Crashlytics، يمكنك النقر فوق مشكلة والحصول على تقرير مفصل عن الحدث. يمكنك تخصيص هذه التقارير لمساعدتك على فهم ما يحدث في تطبيقك بشكل أفضل والظروف المحيطة بالأحداث التي تم الإبلاغ عنها إلى Crashlytics.

  • احصل تلقائيًا على سجلات التنقل إذا كان تطبيقك يستخدم Firebase SDK لـ Google Analytics. تمنحك هذه السجلات إمكانية رؤية إجراءات المستخدم التي سبقت حدث Crashlytics الذي تم جمعه في تطبيقك.

  • قم بإيقاف تشغيل تقارير الأعطال التلقائية وتمكين تقارير الاشتراك للمستخدمين. لاحظ أن Crashlytics، بشكل افتراضي، تقوم تلقائيًا بجمع تقارير الأعطال لجميع مستخدمي تطبيقك.

إضافة مفاتيح مخصصة

تساعدك المفاتيح المخصصة في الحصول على الحالة المحددة لتطبيقك والتي تؤدي إلى حدوث عطل. يمكنك ربط أزواج مفاتيح/قيم عشوائية بتقارير الأعطال، ثم استخدام المفاتيح المخصصة للبحث في تقارير الأعطال وتصفيتها في وحدة تحكم Firebase.

  • في لوحة معلومات Crashlytics ، يمكنك البحث عن المشكلات التي تطابق مفتاحًا مخصصًا.
  • عندما تقوم بمراجعة مشكلة معينة في وحدة التحكم، يمكنك عرض المفاتيح المخصصة المرتبطة بكل حدث (علامة التبويب الفرعية المفاتيح ) وحتى تصفية الأحداث حسب المفاتيح المخصصة (قائمة التصفية في أعلى الصفحة).

استخدم طريقة setCustomValue لتعيين أزواج المفتاح/القيمة. على سبيل المثال:

سويفت

// Set int_key to 100.
Crashlytics.crashlytics().setCustomValue(100, forKey: "int_key")

// Set str_key to "hello".
Crashlytics.crashlytics().setCustomValue("hello", forKey: "str_key")

ج موضوعية

عند تعيين أعداد صحيحة أو منطقية أو عائمة، ضع القيمة في مربع @( 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"];

يمكنك أيضًا تعديل قيمة مفتاح موجود عن طريق استدعاء المفتاح وتعيينه على قيمة مختلفة. على سبيل المثال:

سويفت

Crashlytics.crashlytics().setCustomValue(100, forKey: "int_key")

// Set int_key to 50 from 100.
Crashlytics.crashlytics().setCustomValue(50, forKey: "int_key")

ج موضوعية

[[FIRCrashlytics crashlytics] setCustomValue:@(100) forKey:@"int_key"];

// Set int_key to 50 from 100.
[[FIRCrashlytics crashlytics] setCustomValue:@(50) forKey:@"int_key"];

قم بإضافة أزواج المفاتيح/القيم بشكل مجمّع باستخدام الأسلوب setCustomKeysAndValues ​​مع NSDictionary كمعلمة وحيدة:

سويفت

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)

ج موضوعية

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];

إضافة رسائل السجل المخصصة

لمنح نفسك المزيد من السياق للأحداث التي سبقت حدوث العطل، يمكنك إضافة سجلات Crashlytics مخصصة إلى تطبيقك. يقوم Crashlytics بربط السجلات ببيانات الأعطال الخاصة بك ويعرضها في صفحة Crashlytics بوحدة تحكم Firebase ، ضمن علامة التبويب "السجلات" .

سويفت

استخدم log() أو log(format:, arguments:) للمساعدة في تحديد المشكلات. إذا كنت تريد الحصول على مخرجات سجل مفيدة مع الرسائل، فيجب أن يتوافق الكائن الذي تمرره إلى log() مع خاصية CustomStringConvertible . يُرجع الدالة log() خاصية الوصف التي تحددها للكائن. على سبيل المثال:

Crashlytics.crashlytics().log("Higgs-Boson detected! Bailing out…, \(attributesDict)")

تم إرجاع قيم تنسيقات .log(format:, arguments:) من استدعاء getVaList() . على سبيل المثال:

Crashlytics.crashlytics().log(format: "%@, %@", arguments: getVaList(["Higgs-Boson detected! Bailing out…", attributesDict]))

لمزيد من التفاصيل حول كيفية استخدام log() أو log(format:, arguments:) ، راجع الوثائق المرجعية لـ Crashlytics.

ج موضوعية

استخدم log أو logWithFormat للمساعدة في تحديد المشكلات. لاحظ أنه إذا كنت تريد الحصول على مخرجات سجل مفيدة مع الرسائل، فيجب أن يتجاوز الكائن الذي تمرره إلى أي من الطريقتين خاصية مثيل description . على سبيل المثال:

[[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];

لمزيد من التفاصيل حول كيفية استخدام log و logWithFormat ، راجع الوثائق المرجعية لـ Crashlytics.

تعيين معرفات المستخدم

لتشخيص مشكلة ما، من المفيد غالبًا معرفة المستخدمين الذين تعرضوا لعطل معين. يتضمن Crashlytics طريقة للتعرف على المستخدمين بشكل مجهول في تقارير الأعطال الخاصة بك.

لإضافة معرفات مستخدمين إلى تقاريرك، قم بتعيين معرف فريد لكل مستخدم في شكل رقم معرف أو رمز مميز أو قيمة مجزأة:

سويفت

Crashlytics.crashlytics().setUserID("123456789")

ج موضوعية

[[FIRCrashlytics crashlytics] setUserID:@"123456789"];

إذا احتجت في أي وقت إلى مسح معرف المستخدم بعد تعيينه، فأعد تعيين القيمة إلى سلسلة فارغة. لا يؤدي مسح معرف المستخدم إلى إزالة سجلات Crashlytics الموجودة. إذا كنت بحاجة إلى حذف السجلات المرتبطة بمعرف المستخدم، فاتصل بدعم Firebase .

الإبلاغ عن الاستثناءات غير المميتة

بالإضافة إلى الإبلاغ تلقائيًا عن أعطال تطبيقك، يتيح لك Crashlytics تسجيل الاستثناءات غير القاتلة وإرسالها إليك في المرة التالية التي يتم فيها تشغيل تطبيقك.

يمكنك تسجيل الاستثناءات غير القاتلة عن طريق تسجيل كائنات NSError باستخدام التابع recordError . يلتقط recordError مكدس استدعاءات سلسلة الرسائل عن طريق استدعاء [NSThread callStackReturnAddresses] .

سويفت

Crashlytics.crashlytics().record(error: error)

ج موضوعية

[[FIRCrashlytics crashlytics] recordError:error];

عند استخدام طريقة recordError ، من المهم فهم بنية NSError وكيفية استخدام Crashlytics للبيانات لتجميع الأعطال. يمكن أن يؤدي الاستخدام غير الصحيح للأسلوب recordError إلى سلوك غير متوقع وقد يتسبب في قيام Crashlytics بتقييد الإبلاغ عن الأخطاء المسجلة لتطبيقك.

يحتوي كائن NSError على ثلاث وسائط:

  • domain: String
  • code: Int
  • userInfo: [AnyHashable : Any]? = nil

على عكس الأعطال القاتلة، التي يتم تجميعها عبر تحليل تتبع المكدس، يتم تجميع الأخطاء المسجلة حسب domain code . يعد هذا تمييزًا مهمًا بين الأعطال القاتلة والأخطاء المسجلة. على سبيل المثال:

سويفت

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)

ج موضوعية

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];

عندما تقوم بتسجيل الخطأ أعلاه، فإنه يؤدي إلى إنشاء مشكلة جديدة تم تجميعها حسب NSSomeErrorDomain و -1001 . يتم تجميع الأخطاء المسجلة الإضافية التي تستخدم نفس المجال وقيم التعليمات البرمجية ضمن نفس المشكلة. يتم تحويل البيانات الموجودة في كائن userInfo إلى أزواج قيمة المفتاح ويتم عرضها في قسم المفاتيح/السجلات ضمن مشكلة فردية.

السجلات والمفاتيح المخصصة

تمامًا مثل تقارير الأعطال، يمكنك تضمين السجلات والمفاتيح المخصصة لإضافة سياق إلى NSError . ومع ذلك، هناك اختلاف في السجلات المرفقة بالأعطال مقابل الأخطاء المسجلة. عند حدوث عطل وإعادة تشغيل التطبيق، فإن السجلات التي يستردها Crashlytics من القرص هي تلك التي تمت كتابتها حتى وقت التعطل. عند تسجيل NSError ، لا يتم إنهاء التطبيق على الفور. نظرًا لأن Crashlytics يرسل فقط تقرير الخطأ المسجل عند تشغيل التطبيق التالي ويجب أن يحدد مقدار المساحة المخصصة للسجلات على القرص، فمن الممكن تسجيل ما يكفي بعد تسجيل خطأ NSError بحيث يتم تدوير جميع السجلات ذات الصلة بحلول الوقت الذي يرسل فيه Crashlytics التقرير من الجهاز . ضع هذا التوازن في الاعتبار عند تسجيل NSErrors واستخدام السجلات والمفاتيح المخصصة في تطبيقك.

اعتبارات الأداء

ضع في اعتبارك أن تسجيل NSError قد يكون مكلفًا إلى حد ما. في وقت إجراء المكالمة، يقوم Crashlytics بالتقاط مكدس استدعاءات سلسلة المحادثات الحالية باستخدام عملية تسمى فك المكدس. يمكن أن تتطلب هذه العملية استخدام وحدة المعالجة المركزية (CPU) والإدخال/الإخراج (I/O) بشكل مكثف، خاصة في البنى التي تدعم فك DWARF (arm64 وx86). بعد اكتمال عملية التفكيك، تتم كتابة المعلومات على القرص بشكل متزامن. وهذا يمنع فقدان البيانات في حالة تعطل السطر التالي.

على الرغم من أنه من الآمن استدعاء واجهة برمجة التطبيقات هذه على مؤشر ترابط في الخلفية، تذكر أن إرسال هذا الاستدعاء إلى قائمة انتظار أخرى يفقد سياق تتبع المكدس الحالي.

ماذا عن NSExceptions؟

لا تقدم Crashlytics وسيلة لتسجيل وتسجيل مثيلات NSException مباشرة. بشكل عام، واجهات برمجة تطبيقات Cocoa وCocoa Touch ليست آمنة بشكل استثنائي. وهذا يعني أن استخدام @catch يمكن أن يكون له آثار جانبية خطيرة جدًا غير مقصودة في عمليتك، حتى عند استخدامه بحذر شديد. يجب ألا تستخدم أبدًا عبارات @catch في التعليمات البرمجية الخاصة بك. يرجى الرجوع إلى وثائق Apple حول هذا الموضوع.

تخصيص آثار المكدس

إذا كان تطبيقك يعمل في بيئة غير أصلية (مثل C++ أو Unity)، فيمكنك استخدام Exception Model API للإبلاغ عن بيانات تعريف الأعطال بتنسيق الاستثناء الأصلي لتطبيقك. يتم وضع علامة على الاستثناءات المبلغ عنها على أنها غير مميتة.

سويفت

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)

ج موضوعية

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];

يمكن أيضًا تهيئة إطارات المكدس المخصصة بالعناوين فقط:

سويفت

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)

ج موضوعية

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];

الحصول على سجلات مسار التنقل

تمنحك سجلات التنقل فهمًا أفضل للتفاعلات التي أجراها المستخدم مع تطبيقك والتي أدت إلى حدوث عطل أو حدث غير مميت أو ANR. يمكن أن تكون هذه السجلات مفيدة عند محاولة إعادة إنتاج مشكلة ما وتصحيح أخطائها.

يتم تشغيل سجلات التنقل بواسطة Google Analytics، لذا للحصول على سجلات التنقل، تحتاج إلى تمكين Google Analytics لمشروع Firebase الخاص بك وإضافة Firebase SDK لـ Google Analytics إلى تطبيقك. بمجرد استيفاء هذه المتطلبات، يتم تضمين سجلات التنقل تلقائيًا مع بيانات الحدث ضمن علامة التبويب "السجلات" عند عرض تفاصيل المشكلة.

تقوم Analytics SDK تلقائيًا بتسجيل حدث screen_view الذي يمكّن سجلات مسار التنقل من عرض قائمة بالشاشات التي تم عرضها قبل حدث العطل أو الحدث غير الفادح أو حدث ANR. يحتوي سجل مسار التنقل screen_view على معلمة firebase_screen_class .

تتم أيضًا تعبئة سجلات التنقل التفصيلي بأي أحداث مخصصة تقوم بتسجيلها يدويًا خلال جلسة المستخدم، بما في ذلك بيانات معلمات الحدث. يمكن أن تساعد هذه البيانات في إظهار سلسلة من إجراءات المستخدم التي تؤدي إلى حدوث عطل أو حدث غير مميت أو حدث ANR.

لاحظ أنه يمكنك التحكم في جمع واستخدام بيانات Google Analytics ، والتي تتضمن البيانات التي تملأ سجلات التنقل.

تمكين الاشتراك في التقارير

افتراضيًا، يقوم Crashlytics تلقائيًا بجمع تقارير الأعطال لجميع مستخدمي تطبيقك. لمنح المستخدمين المزيد من التحكم في البيانات التي يرسلونها، يمكنك تمكين إعداد التقارير عن طريق تعطيل التقارير التلقائية وإرسال البيانات إلى Crashlytics فقط عندما تختار ذلك في التعليمات البرمجية الخاصة بك:

  1. قم بإيقاف تشغيل التجميع التلقائي عن طريق إضافة مفتاح جديد إلى ملف Info.plist الخاص بك:

    • المفتاح: FirebaseCrashlyticsCollectionEnabled
    • القيمة: false
  2. قم بتمكين التجميع لمستخدمين محددين عن طريق استدعاء تجاوز مجموعة بيانات Crashlytics في وقت التشغيل. تستمر قيمة التجاوز عبر عمليات تشغيل تطبيقك حتى يتمكن Crashlytics من جمع التقارير تلقائيًا.

    لإلغاء الاشتراك في إعداد تقارير الأعطال التلقائية، قم بتمرير false كقيمة التجاوز. عند التعيين على false ، لا يتم تطبيق القيمة الجديدة حتى التشغيل التالي للتطبيق.

    سويفت

    Crashlytics.crashlytics().setCrashlyticsCollectionEnabled(true)

    ج موضوعية

    [[FIRCrashlytics crashlytics] setCrashlyticsCollectionEnabled:YES];

إدارة بيانات Crash Insights

تساعدك Crash Insights على حل المشكلات عن طريق مقارنة تتبعات المكدس المجهولة الهوية بالتتبعات من تطبيقات Firebase الأخرى وإعلامك بما إذا كانت مشكلتك جزءًا من اتجاه أكبر. بالنسبة للعديد من المشكلات، توفر Crash Insights أيضًا موارد لمساعدتك في تصحيح أخطاء العطل.

يستخدم Crash Insights بيانات الأعطال المجمعة لتحديد اتجاهات الاستقرار الشائعة. إذا كنت تفضل عدم مشاركة بيانات تطبيقك، فيمكنك إلغاء الاشتراك في Crash Insights من قائمة Crash Insights الموجودة أعلى قائمة مشكلات Crashlytics في وحدة تحكم Firebase .