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

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

  • احصل على سجلات شريط التنقل تلقائيًا إذا كان تطبيقك يستخدم حزمة تطوير البرامج (SDK) لمنصّة Firebase الخاصّة بخدمة "إحصاءات Google". تمنحك هذه السجلات إمكانية الاطّلاع على إجراءات المستخدمين التي تؤدي إلى حدث يجمعه 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، تمامًا مثل تقارير الأعطال. ومع ذلك، هناك فرق في السجلات المرفقة بالأعطال مقابل الأخطاء المسجّلة. عند حدوث عطل وإعادة تشغيل التطبيق، فإن سجلات Crashlytics التي يستردها من القرص هي تلك التي تمت كتابتها حتى وقت العطل. عند تسجيل NSError، لا يتم إنهاء التطبيق على الفور. ولأن Crashlytics لا يرسل إلا تقرير الأخطاء المسجّل عند إطلاق التطبيق التالي ويجب أن يحد من المساحة المخصصة للسجلات على القرص، فمن الممكن تسجيل ما يكفي بعد تسجيل NSError كي يتم تبديل جميع السجلات ذات الصلة بحلول الوقت الذي يرسل فيه Crashlytics التقرير من الجهاز. ضَع هذا الرصيد في الاعتبار عند تسجيل الدخول إلى NSErrors واستخدام السجلات والمفاتيح المخصّصة في تطبيقك.

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

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

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

ماذا عن NSالاستثناءات؟

لا يوفر تطبيق Crashlytics وسيلة لتسجيل مثيلات NSException وتسجيلها مباشرةً. بشكل عام، لا يمكن لواجهات برمجة تطبيقات Cocoa وCocoa Touch أن ويعني هذا أنّ استخدام @catch قد ينتج عنه آثار جانبية خطيرة جدًا غير مقصودة في العملية، حتى عند استخدامه بحذر شديد. يجب عدم استخدام عبارات @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" إلى تطبيقك. بعد استيفاء هذه المتطلبات، يتم تضمين سجلّات شريط التنقّل تلقائيًا مع بيانات الحدث ضمن علامة التبويب السجلات عند عرض تفاصيل المشكلة.

إنّ حزمة تطوير البرامج (SDK) لخدمة "إحصاءات Google" تسجّل تلقائيًا حدث screen_view التي تتيح لسجلّات شريط التنقّل عرض قائمة بالشاشات التي تمت مشاهدتها قبل حدوث الأعطال أو غير الفادحة أو حدث ANR. يحتوي سجلّ شريط التنقّل screen_view على مَعلمة firebase_screen_class.

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

تجدر الإشارة إلى أنّه يمكنك التحكّم في جمع بيانات "إحصاءات Google" واستخدامها، التي تتضمّن البيانات التي تُعبّئ سجلّات شريط التنقّل.

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

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

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

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

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

    Swift

    Crashlytics.crashlytics().setCrashlyticsCollectionEnabled(true)

    Objective-C

    [[FIRCrashlytics crashlytics] setCrashlyticsCollectionEnabled:YES];

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

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

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