ปรับแต่งรายงานข้อขัดข้องสำหรับแพลตฟอร์ม Apple

เลือกแพลตฟอร์ม iOS+ Android Flutter Unity


คุณสามารถคลิกปัญหาเพื่อดูรายงานเหตุการณ์โดยละเอียดได้ในแดชบอร์ด DevOps และการมีส่วนร่วม > Crashlytics ของคอนโซล Firebase คุณสามารถปรับแต่งรายงานเหล่านั้นเพื่อช่วยให้เข้าใจสิ่งที่เกิดขึ้นในแอปและสถานการณ์เกี่ยวกับเหตุการณ์ที่รายงานไปยัง Crashlytics ได้ดียิ่งขึ้น

เพิ่มคีย์ที่กำหนดเอง

คีย์ที่กำหนดเองช่วยให้คุณทราบสถานะที่เฉพาะเจาะจงของแอปที่นำไปสู่ข้อขัดข้อง คุณสามารถเชื่อมโยงคู่คีย์-ค่าที่กำหนดเองกับรายงานข้อขัดข้อง จากนั้นใช้คีย์ที่กำหนดเองเพื่อค้นหาและกรองรายงานข้อขัดข้องในแดชบอร์ด DevOps และการมีส่วนร่วม > Crashlytics ของคอนโซล Firebase

  • คุณสามารถค้นหาปัญหาที่ตรงกับคีย์ที่กำหนดเองได้

  • เมื่อตรวจสอบปัญหาที่เฉพาะเจาะจงในคอนโซล คุณจะดูคีย์ที่กำหนดเองที่เชื่อมโยงสำหรับแต่ละเหตุการณ์ได้ (แท็บย่อยคีย์) และยังกรองเหตุการณ์ตามคีย์ที่กำหนดเองได้ด้วย (เมนูตัวกรองที่ด้านบนของหน้า)

ใช้เมธอด 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 จะเชื่อมโยงบันทึกกับข้อมูลข้อขัดข้องและแสดงในแท็บบันทึกเมื่อคุณดูรายละเอียดของปัญหา (ดูปัญหาทั้งหมดในแดชบอร์ดDevOps และการมีส่วนร่วม > 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 มีอาร์กิวเมนต์ 3 รายการดังนี้

  • 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 และ I/O อย่างหนัก โดยเฉพาะในสถาปัตยกรรมที่รองรับการคลาย DWARF (arm64 และ x86) หลังจากคลายข้อมูลเสร็จแล้ว ระบบจะเขียนข้อมูลลงในดิสก์พร้อมกัน ซึ่งจะช่วยป้องกันไม่ให้ข้อมูลสูญหายหากบรรทัดถัดไปขัดข้อง

แม้ว่าการเรียก API นี้ในชุดข้อความเบื้องหลังจะปลอดภัย แต่โปรดทราบว่าการส่งการเรียกนี้ไปยังคิวอื่นจะทำให้บริบทของสแต็กเทรซปัจจุบันหายไป

แล้ว NSExceptions ล่ะ

Crashlytics ไม่มีเครื่องมือสำหรับการบันทึกและจัดเก็บอินสแตนซ์ NSException โดยตรง โดยทั่วไปแล้ว Cocoa และ Cocoa Touch API ไม่ปลอดภัยจากข้อยกเว้น ซึ่งหมายความว่าการใช้ @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 Analytics ดังนั้นหากต้องการรับบันทึกเบรดครัมบ์ คุณต้องเปิดใช้ Google Analytics สำหรับโปรเจ็กต์ Firebase และเพิ่ม Firebase SDK สำหรับ Google Analytics ลงในแอป เมื่อเป็นไปตามข้อกำหนดเหล่านี้แล้ว บันทึกเบรดครัมบ์จะรวมอยู่ในข้อมูลของเหตุการณ์โดยอัตโนมัติภายในแท็บบันทึกเมื่อคุณดูรายละเอียดของปัญหา (ดูปัญหาทั้งหมดในแดชบอร์ดDevOps และการมีส่วนร่วม > Crashlytics ของคอนโซล Firebase)

SDK ของ Analytics จะบันทึกเหตุการณ์ screen_view โดยอัตโนมัติ ซึ่งช่วยให้บันทึกเบรดครัมบ์แสดงรายการหน้าจอที่ดูก่อนเกิดเหตุการณ์ข้อขัดข้อง ข้อผิดพลาดที่ไม่ร้ายแรง หรือ ANR บันทึกเบรดครัมบ์ screen_view มีพารามิเตอร์ firebase_screen_class

นอกจากนี้ บันทึกเบรดครัมบ์ยังสร้างขึ้นจากเหตุการณ์ที่กำหนดเองที่คุณบันทึกด้วยตนเองภายในเซสชันของผู้ใช้ รวมถึงข้อมูลพารามิเตอร์ของเหตุการณ์ด้วย ข้อมูลนี้จะช่วยแสดงชุดการดำเนินการของผู้ใช้ที่นำไปสู่เหตุการณ์ข้อขัดข้อง เหตุการณ์ที่ไม่ร้ายแรง หรือเหตุการณ์ ANR

โปรดทราบว่าคุณสามารถควบคุมการรวบรวมและการใช้ข้อมูล Google Analytics ซึ่งรวมถึงข้อมูลที่สร้างบันทึกเบรดครัมบ์ได้

เปิดใช้การรายงานการเลือกใช้

โดยค่าเริ่มต้น Crashlytics จะรวบรวมรายงานข้อขัดข้องสำหรับผู้ใช้แอปทั้งหมดโดยอัตโนมัติ หากต้องการให้ผู้ใช้ควบคุมข้อมูลที่ส่งได้มากขึ้น คุณสามารถเปิดใช้การรายงานแบบเลือกรับโดยปิดใช้การรายงานอัตโนมัติ และส่งข้อมูลไปยัง Crashlytics เมื่อคุณเลือกในโค้ดเท่านั้น

  1. ปิดการรวบรวมอัตโนมัติโดยเพิ่มคีย์ใหม่ลงในไฟล์ Info.plist ดังนี้

    • แป้น: FirebaseCrashlyticsCollectionEnabled
    • ค่า: false
  2. เปิดใช้การเก็บรวบรวมข้อมูลสำหรับผู้ใช้บางรายโดยเรียกใช้การลบล้างการเก็บรวบรวมข้อมูล Crashlytics ขณะรันไทม์ ค่าการลบล้างจะคงอยู่ตลอดการเปิดแอปครั้งต่อๆ ไปทั้งหมด เพื่อให้ Crashlytics รวบรวมรายงานสำหรับผู้ใช้รายนั้นได้โดยอัตโนมัติ

    Swift

    Crashlytics.crashlytics().setCrashlyticsCollectionEnabled(true)

    Objective-C

    [[FIRCrashlytics crashlytics] setCrashlyticsCollectionEnabled:YES];

    หากผู้ใช้เลือกไม่ให้เก็บรวบรวมข้อมูลในภายหลัง คุณสามารถส่ง false เป็นค่าลบล้าง ซึ่งจะมีผลในครั้งถัดไปที่ผู้ใช้เปิดแอป และจะยังคงมีผลในการเปิดแอปครั้งต่อๆ ไปทั้งหมดสำหรับผู้ใช้รายนั้น

จัดการข้อมูล Crash Insights

Crash Insights ช่วยคุณแก้ปัญหาโดยการเปรียบเทียบสแต็กเทรซที่ลบข้อมูลระบุตัวบุคคลของคุณกับสแต็กเทรซจากแอป Firebase อื่นๆ และแจ้งให้คุณทราบว่าปัญหาของคุณเป็นส่วนหนึ่งของแนวโน้มที่ใหญ่ขึ้นหรือไม่ สำหรับปัญหาหลายๆ อย่าง Crash Insights ยังมีแหล่งข้อมูลที่จะช่วยคุณแก้ไขข้อบกพร่องของข้อขัดข้องด้วย

Crash Insights ใช้ข้อมูลข้อขัดข้องที่รวบรวมไว้เพื่อระบุแนวโน้มความเสถียรที่พบบ่อย หากไม่ต้องการแชร์ข้อมูลของแอป คุณสามารถเลือกไม่ใช้ข้อมูลเชิงลึกเกี่ยวกับข้อขัดข้องได้จากเมนูข้อมูลเชิงลึกเกี่ยวกับข้อขัดข้องที่ด้านบนของรายการปัญหาในแดชบอร์ดDevOps และการมีส่วนร่วม > Crashlytics ของคอนโซล Firebase

ขั้นตอนถัดไป

  • ส่งออกข้อมูลไปยัง BigQuery หรือ Cloud Logging เพื่อใช้การวิเคราะห์และฟีเจอร์ขั้นสูง เช่น การค้นหาข้อมูล การสร้างแดชบอร์ดที่กำหนดเอง และการตั้งค่าการแจ้งเตือนที่กำหนดเอง