تخصيص تقارير أعطال Firebase Crashlytics


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

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

  • أوقِف ميزة إعداد تقارير الأعطال التلقائية وفعِّل ميزة إعداد التقارير عند الموافقة للمستخدمين. يُرجى العلم أنّه يتم تلقائيًا جمع Crashlytics لتقارير الأعطال لجميع مستخدمي تطبيقك.

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

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

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

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

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

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

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

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

أضِف أزواج المفتاح/القيمة بشكلٍ مجمّع باستخدام طريقة setCustomKeysAndValues مع NSDictionary كمَعلمة وحيدة:

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

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

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

Swift

ويمكنك استخدام 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 المستندات المرجعية.

Objective-C

استخدِم 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 يتضمّن طريقة لتحديد هوية المستخدمين بدون الكشف عن هويتهم في تقارير الأعطال.

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

Swift

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

Objective-C

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

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

الإبلاغ عن الاستثناءات غير الفادحة

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

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

Swift

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

Objective-C

[[FIRCrashlytics crashlytics] recordError:error];

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

يتضمّن عنصر NSError ثلاث وسيطات:

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

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

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

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

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

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

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

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

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

ماذا عن NSExceptions؟

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

تخصيص قوائم تتبُّع تسلسل استدعاء الدوال البرمجية

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

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

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

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

الحصول على سجلّات أشرطة التنقّل

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

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

تسجِّل حزمة تطوير البرامج (SDK) لنظام التشغيل Analytics حدث screen_view تلقائيًا، ما يتيح لسجلّات مسار التنقّل عرض قائمة بالشاشات التي تمّ عرضها قبل حدث تعطُّل أو حدث خطأ غير قاتل أو حدث ANR. يحتوي سجلّ screen_view على مَعلمة firebase_screen_class.

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

تجدر الإشارة إلى أنّه يمكنك التحكّم في جمع بيانات Google Analytics واستخدامها، بما في ذلك البيانات التي تملأ سجلّات مسار التنقّل.

تفعيل إعداد تقارير الموافقة

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

  1. أوقِف عملية الجمع التلقائي عن طريق إضافة مفتاح جديد إلى ملف Info.plist:

    • المفتاح: FirebaseCrashlyticsCollectionEnabled
    • القيمة: false
  2. يمكنك تفعيل عملية جمع البيانات لمستخدمين محدّدين من خلال استدعاء Crashlytics data collection override أثناء التشغيل. وتستمر قيمة الإلغاء في جميع إصدارات تطبيقك حتى يتمكّن Crashlytics من جمع التقارير تلقائيًا.

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

    Swift

    Crashlytics.crashlytics().setCrashlyticsCollectionEnabled(true)

    Objective-C

    [[FIRCrashlytics crashlytics] setCrashlyticsCollectionEnabled:YES];

إدارة بيانات "إحصاءات الأعطال"

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

تستخدِم ميزة "إحصاءات الأعطال" بيانات الأعطال المجمّعة لتحديد المؤشرات الشائعة للاستقرار. إذا كنت تفضّل عدم مشاركة بيانات تطبيقك، يمكنك إيقاف ميزة "إحصاءات الأعطال" من قائمة إحصاءات الأعطال في أعلى قائمة CrashlyticsCrashlytics في وحدة تحكّم Firebase.