เป็นความจริงหรือไม่ที่ไม่ควรใช้ NSLog () กับรหัสการผลิต


155

ฉันได้รับแจ้งจากเว็บไซต์นี้สองสามครั้ง แต่ฉันต้องการให้แน่ใจว่านี่เป็นกรณีจริง ๆ

ฉันคาดหวังว่าจะสามารถโรยฟังก์ชั่นการเรียก NSLog ตลอดทั้งรหัสของฉันและ Xcode / gcc จะตัดการโทรเหล่านั้นออกโดยอัตโนมัติเมื่อสร้างรุ่นวางจำหน่าย / การกระจายของฉัน

ฉันควรหลีกเลี่ยงการใช้สิ่งนี้หรือไม่? ถ้าเป็นเช่นนั้นมีทางเลือกอะไรมากที่สุดระหว่างโปรแกรมเมอร์ Objective-C ที่มีประสบการณ์?


7
ฉันรู้ว่าคำถามนี้ตอนนี้เก่ามาก แต่ถ้าคุณยังสามารถฉันจะทำเครื่องหมายคำตอบของ Marc Charbonneau เป็นที่ยอมรับ ฉันได้แก้ไขคำตอบของฉันให้ชี้ไปที่เขา แต่คำตอบของเขาคือคำตอบที่ถูกต้อง
e.James

5
NSLog () ภายในวงวนบ่อยๆจะฆ่าการแสดงของคุณอย่างแน่นอนเขาพบว่าวิธีที่ยากลำบาก
willc2

คำตอบ:


197

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

#define DEBUG_MODE

#ifdef DEBUG_MODE
    #define DebugLog( s, ... ) NSLog( @"<%p %@:(%d)> %@", self, [[NSString stringWithUTF8String:__FILE__] lastPathComponent], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] )
#else
    #define DebugLog( s, ... ) 
#endif

ฉันพบว่าการใส่คำสั่งทั้งหมดนี้ไว้ในส่วนหัวของคำนำหน้าง่ายกว่าการใส่ไฟล์ของตัวเอง คุณสามารถสร้างระบบการบันทึกที่ซับซ้อนมากขึ้นได้โดยให้ DebugLog โต้ตอบกับวัตถุ Objective-C ปกติ ตัวอย่างเช่นคุณอาจมีคลาสการบันทึกที่เขียนไปยังไฟล์บันทึกของตนเอง (หรือฐานข้อมูล) และรวมถึงอาร์กิวเมนต์ 'ลำดับความสำคัญ' ที่คุณสามารถตั้งค่าได้ที่รันไทม์ดังนั้นข้อความดีบั๊กจะไม่แสดงในเวอร์ชันรีลีสของคุณ หากคุณทำสิ่งนี้คุณสามารถสร้าง DebugLog (), WarningLog () และอื่น ๆ )

โอ้และจำไว้ว่า#define DEBUG_MODEสามารถนำมาใช้ใหม่ได้ในที่ต่างๆในแอปพลิเคชันของคุณ ตัวอย่างเช่นในแอปพลิเคชันของฉันฉันใช้เพื่อปิดใช้งานการตรวจสอบคีย์ใบอนุญาตและอนุญาตให้แอปพลิเคชันทำงานหากว่าก่อนวันที่กำหนด สิ่งนี้ทำให้ฉันสามารถแจกจ่ายสำเนาเบต้าที่มีเวลา จำกัด และทำงานได้อย่างเต็มที่โดยใช้ความพยายามของฉันน้อยที่สุด


8
+1 สำหรับคำตอบที่ยอดเยี่ยม ฉันเปลี่ยนของฉันเพื่อระบุว่า #define macros ของคุณเป็นวิธีที่จะไปและฉันหวังว่า OP จะเปลี่ยนคำตอบที่ยอมรับได้ (ฉันทิ้งความคิดเห็นไว้) ฉันใช้ฟังก์ชันดัมมี่เพราะฉันไม่รู้ว่าคุณสามารถใช้ ... อาร์กิวเมนต์ในมาโครได้ อยู่และเรียนรู้!
e.James

15
คำตอบที่ยอดเยี่ยมถึงแม้ว่าฉันขอแนะนำให้ใช้คำนำหน้าส่วนบุคคลในการกำหนด "DEBUG_MODE" ของคุณเช่นเรียกว่า "JPM_DEBUG" หรือสิ่งอื่นที่คล้ายกัน บ่อยครั้งที่ฉันพบรหัสบุคคลที่สามที่ใช้ DEBUG หรือ DEBUG_MODE หรือรหัสอื่นที่คล้ายกันและบางครั้งรหัสนั้นอาจทำงานไม่ถูกต้องในโหมด DEBUG หากคุณต้องการเปิดใช้งานการดีบักไลบรารีบุคคลที่สามคุณควรทำเช่นนั้นโดยเจตนา (แน่นอนว่าเป็นนักเขียนห้องสมุดที่ควรใส่สัญลักษณ์ของตนไว้ล่วงหน้า แต่เฟรมเวิร์ก C และ C ++ จำนวนมากไม่ได้ทำโดยเฉพาะอย่างยิ่งสำหรับการกำหนดนี้)
Rob Napier

1
มีแมโคร Xcode ที่กำหนดไว้ล่วงหน้าที่สามารถใช้เพื่อเปิดใช้งานนี้เฉพาะเมื่อมีการตั้งค่าการกำหนดค่าให้ดีบั๊กหรือไม่ ฉันไม่ต้องการตั้งค่ามาโครตัวประมวลผลล่วงหน้านี้ด้วยตนเองในทุกโครงการ เราสามารถทำบางสิ่งเช่นการติดตาม pseudocode #if XCODE_CONFIGURATION == DEBUG ได้หรือไม่
frankodwyer

1
#include <TargetConditionals.h>
slf

2
วิธีการนี้นำไปสู่การเตือน "ตัวแปรที่ไม่ได้ใช้" ปลอมจากคอมไพเลอร์ในโหมดรีลีสเมื่อคำสั่งการบันทึกใช้ตัวแปรตัวกลางเพื่อจุดประสงค์เดียวในการคำนวณค่าเพื่อบันทึก อะไรจะเป็นวิธีที่ฉลาดที่สุดในการหลีกเลี่ยงว่าถ้าคุณเกลียดคำเตือนของคอมไพเลอร์เท่าที่ฉันทำ
Jean-Denis Muys

78

ใส่ 3 บรรทัดนี้ท้ายไฟล์ -prefix.pch:

#ifndef DEBUG
  #define NSLog(...) /* suppress NSLog when in release mode */
#endif

คุณไม่จำเป็นต้องกำหนดสิ่งใดในโครงการของคุณเนื่องจากDEBUGกำหนดไว้ในการตั้งค่าการสร้างตามค่าเริ่มต้นเมื่อคุณสร้างโครงการ


2
ไกลทางออกที่ดีที่สุด คุณต้องเพิ่ม prefix.pch ด้วยตนเองจาก XCode 6
Teddy

เรายังต้องเปลี่ยนการตั้งค่าการสร้างก่อนปล่อยเช่น debug to release
UserDev

25

การโทร NSLog สามารถอยู่ในรหัสการผลิตได้ แต่ควรจะมีเฉพาะกรณีพิเศษหรือข้อมูลที่ต้องการซึ่งจะถูกบันทึกไว้ในบันทึกของระบบ

แอปพลิเคชั่นที่ทิ้งขยะบันทึกของระบบนั้นน่ารำคาญและพบว่าไม่เป็นมืออาชีพ


14
ขอโทษด้วย - ไม่เป็นมืออาชีพกับใคร ใครมีแนวโน้มที่จะตรวจสอบบันทึกของคุณในแอปที่เผยแพร่และตัดสินความเป็นมืออาชีพของคุณตามนั้น (เพื่อความชัดเจนฉันเห็นด้วยอย่างยิ่งว่าคุณไม่ควรเก็บ NSLogs ไว้ในแอปพลิเคชันของคุณ แต่ฉันสับสนกับข้อโต้แย้ง 'ความเป็นมืออาชีพ')
WendiKidd

4
นักพัฒนาคนอื่นจะทำในสิ่งที่คุณทำและรู้สึกรำคาญ Android มีปัญหาคล้ายกันกับนักพัฒนาบางคนที่ไม่ดีplus.google.com/110166527124367568225/posts/h4jK38n4XYR
Roger Binns

24

ฉันไม่สามารถออกความเห็นเกี่ยวกับคำตอบของ Marc Charbonneauดังนั้นฉันจะโพสต์สิ่งนี้เป็นคำตอบ

นอกจากนี้การเพิ่มแมโครที่ส่วนหัวก่อนรวบรวมของคุณคุณสามารถใช้สร้างเป้าหมายการกำหนดค่าเพื่อควบคุมการกำหนด (หรือขาดการกำหนด)DEBUG_MODE

หากคุณเลือกการกำหนดค่าที่ใช้งานอยู่ " Debug " DEBUG_MODEจะถูกกำหนดและแมโครจะขยายเป็นNSLogนิยามแบบเต็ม

การเลือกการกำหนดค่าแบบแอคทีฟ " Release " จะไม่ถูกกำหนดDEBUG_MODEและNSLogging ของคุณจะถูกละไว้จากการสร้างรีลีส

ขั้นตอน:

  • เป้าหมาย> รับข้อมูล
  • แท็บสร้าง
  • ค้นหา "มาโครตัวประมวลผลล่วงหน้า" (หรือGCC_PREPROCESSOR_DEFINITIONS)
  • เลือกการกำหนดค่า: ดีบัก
  • แก้ไขคำจำกัดความที่ระดับนี้
  • เพิ่ม DEBUG_MODE=1
  • เลือกการกำหนดค่า: ปล่อย
  • ยืนยันDEBUG_MODEไม่ได้ตั้งค่าGCC_PREPROCESSOR_DEFINITIONS

หากคุณละเว้นอักขระ '=' ในคำนิยามคุณจะได้รับข้อผิดพลาดจากตัวประมวลผลล่วงหน้า

นอกจากนี้ให้วางความคิดเห็นนี้ (แสดงด้านล่าง) เหนือคำจำกัดความของมาโครเพื่อเตือนให้คุณทราบว่าDEBUG_MACROมาจากไหน;

// Target > Get Info > Build > GCC_PREPROCESSOR_DEFINITIONS
// Configuration = Release: <empty>
//               = Debug:   DEBUG_MODE=1

1
มันเป็นคำตอบเพิ่มเติมที่มีค่าสำหรับคำถาม สมควรที่จะเป็นมากกว่าความคิดเห็น
Morningstar

DEBUG_MODEและDEBUG_MACROไม่เป็นทางการ ฉันพบการอ้างอิงถึงDEBUG_MACROไซต์ของ apple เท่านั้น ( opensource.apple.com/source/gm4/gm4-15/src/m4.h?txt ) บางทีมาตรฐานมากขึ้นDEBUGและNDEBUGจะเป็นทางเลือกที่ดีกว่า NDEBUGถูกระบุโดย Posix; ในขณะที่DEBUGถูกใช้โดยการประชุม
jww

+1 ใช่นี่คือโพสต์เก่า แต่นั่นเป็นประเด็น ... ในเวอร์ชัน Xcode ของฉัน (4 ปีต่อมา) การค้นหา GCC_PREPROCESSOR_DEFINITIONS ส่งคืนภาษาที่แตกต่างกัน โปรดลองอัปเดตคำตอบที่ยอดเยี่ยมนี้เพื่อความชัดเจน
เดวิด

11

แก้ไข: วิธีการโพสต์โดยมาร์ค Charbonneauและนำไปสู่ความสนใจของฉันโดยShoอยู่ไกลดีกว่านี้

ฉันได้ลบบางส่วนของคำตอบที่แนะนำโดยใช้ฟังก์ชันว่างเปล่าเพื่อปิดใช้งานการบันทึกเมื่อปิดใช้งานโหมดแก้ไขข้อบกพร่อง ส่วนที่เกี่ยวข้องกับการตั้งค่ามาโครตัวประมวลผลล่วงหน้าอัตโนมัติยังคงมีความเกี่ยวข้องดังนั้นจึงยังคงอยู่ ฉันยังแก้ไขชื่อของมาโครตัวประมวลผลล่วงหน้าเพื่อให้เหมาะสมกับคำตอบของ Marc Charbonneau


เพื่อให้บรรลุพฤติกรรมอัตโนมัติ (และคาดว่า) ใน Xcode:

ในการตั้งค่าโครงการให้ไปที่แท็บ "สร้าง" และเลือกการกำหนดค่า "ดีบั๊ก" หาส่วน "Preprocessor แมโคร" DEBUG_MODEและเพิ่มชื่อแมโคร

...

แก้ไข:ดูคำตอบของ Marc Charbonneauสำหรับวิธีการที่เหมาะสมในการเปิดใช้งานและปิดใช้งานการบันทึกด้วยDEBUG_MODEมาโคร


7

ฉันเห็นด้วยกับแมทธิว ไม่มีอะไรผิดปกติกับ NSLog ในรหัสการผลิต ในความเป็นจริงมันจะมีประโยชน์กับผู้ใช้ ที่กล่าวว่าหากเหตุผลเดียวที่คุณใช้ NSLog คือช่วยแก้ไขข้อบกพร่องใช่แล้วควรลบออกก่อนที่คุณจะเผยแพร่

นอกจากนี้เนื่องจากคุณติดแท็กคำถามนี้เป็นคำถาม iPhone, NSLog ใช้ทรัพยากรซึ่งเป็นสิ่งที่ iPhone มีค่าเล็กน้อย หากคุณกำลังใช้ NSLogging ทุกอย่างบน iPhone นั่นจะเป็นการลดเวลาประมวลผลจากแอพของคุณ ใช้มันอย่างชาญฉลาด


4

ความจริงง่ายๆคือ NSLog นั้นค่อนข้างช้า

แต่ทำไม ในการตอบคำถามนั้นเรามาดูกันว่า NSLog ทำอะไรได้บ้างแล้วทำอย่างไร

NSLog ทำอะไรกันแน่

NSLog ทำ 2 สิ่ง:

มันเขียนข้อความบันทึกไปยังสิ่งอำนวยความสะดวกของ Apple System Logging (asl) สิ่งนี้อนุญาตให้ข้อความบันทึกแสดงขึ้นใน Console.app นอกจากนี้ยังตรวจสอบเพื่อดูว่ากระแส stderr ของแอปพลิเคชันจะไปที่เทอร์มินัลหรือไม่ (เช่นเมื่อแอปพลิเคชันกำลังทำงานผ่าน Xcode) หากเป็นเช่นนั้นจะเขียนข้อความบันทึกไปยัง stderr (เพื่อให้ปรากฏในคอนโซล Xcode)

การเขียนไปยัง STDERR นั้นฟังดูไม่ยาก ที่สามารถทำได้ด้วย fprintf และการอ้างอิง descriptor ไฟล์ stderr แต่แล้ว ASL ล่ะ?

เอกสารที่ดีที่สุดที่ฉันได้พบเกี่ยวกับ ASL คือโพสต์บล็อก 10 ส่วนจาก Peter Hosey: ลิงก์

ไฮไลต์ (ตามที่เกี่ยวข้องกับประสิทธิภาพ) คือ:

ในการส่งข้อความบันทึกไปยังสิ่งอำนวยความสะดวก ASL โดยทั่วไปแล้วคุณเปิดการเชื่อมต่อลูกค้าไปยัง ASL daemon และส่งข้อความ แต่ - แต่ละเธรดต้องใช้การเชื่อมต่อไคลเอนต์แยกต่างหาก ดังนั้นเพื่อความปลอดภัยของเธรดทุกครั้งที่เรียกว่า NSLog จะเป็นการเปิดการเชื่อมต่อไคลเอนต์ asl ใหม่ส่งข้อความแล้วปิดการเชื่อมต่อ

ทรัพยากรอาจจะพบได้ที่นี่และที่นี่


แก้ไขข้อความ ทรัพยากรจำเป็นต้องอยู่ในส่วนท้ายเท่านั้น
Johan Karlsson

2

ตามที่ระบุไว้ในคำตอบอื่น ๆ คุณสามารถใช้ #define เพื่อเปลี่ยนว่า NSLog ใช้หรือไม่ในเวลารวบรวม

อย่างไรก็ตามวิธีที่ยืดหยุ่นกว่าคือการใช้ไลบรารีการบันทึกเช่นCocoa Lumberjackซึ่งจะช่วยให้คุณเปลี่ยนแปลงไม่ว่าจะมีบางสิ่งที่ถูกบันทึกในรันไทม์เช่นกัน

ในรหัสของคุณแทนที่ NSLog โดย DDLogVerbose หรือ DDLogError ฯลฯ เพิ่ม #import สำหรับนิยามแมโคร ฯลฯ และตั้งค่าตัวบันทึกบ่อยครั้งในเมธอด applicationDidFinishLaunching

เพื่อให้มีผลเช่นเดียวกับ NSLog รหัสการกำหนดค่าคือ

[DDLog addLogger:[DDASLLogger sharedInstance]];
[DDLog addLogger:[DDTTYLogger sharedInstance]];

2

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

จากมุมมองของการตรวจสอบบัญชีผู้สอบบัญชีไม่ต้องการดูการใช้งานแต่ละครั้งNSLogเพื่อให้แน่ใจว่าไม่ได้บันทึกข้อมูลที่ละเอียดอ่อน เขา / เธอจะบอกให้คุณลบคนตัดไม้ออก

ฉันทำงานกับทั้งสองกลุ่ม เราตรวจสอบรหัสเขียนคู่มือการเข้ารหัส ฯลฯ คู่มือของเราต้องการให้การบันทึกถูกปิดใช้งานในรหัสการผลิต ดังนั้นทีมภายในไม่ควรลอง;)

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

และจำไว้ว่าเรานิยาม 'ละเอียดอ่อน' ไม่ใช่นักพัฒนา;)

ฉันยังรับรู้แอปที่มีการบันทึกจำนวนมากเป็นแอพที่พร้อมจะทำการระเบิด มีเหตุผลที่ต้องทำการบันทึก / จำเป็นอย่างมากและมักจะไม่เสถียร มันอยู่ที่นั่นด้วย 'watchdog' กระทู้ที่เริ่มบริการแขวน

หากคุณไม่เคยผ่านการตรวจสอบความปลอดภัยของสถาปัตยกรรม (SecArch) สิ่งเหล่านี้คือสิ่งที่เรามอง


1

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


1

โปรดทราบว่า NSLogs สามารถชะลอ UI / เธรดหลักได้ เป็นการดีที่สุดที่จะลบออกจาก builds เว้นแต่ว่าจำเป็นจริงๆ


0

ฉันขอแนะนำอย่างยิ่งให้ใช้ TestFlight สำหรับการบันทึก (ฟรี) วิธีการของพวกเขาจะแทนที่ NSLog (โดยใช้มาโคร) และอนุญาตให้คุณเปิด / ปิดการบันทึกไปยังเซิร์ฟเวอร์บันทึก Apple System และบันทึก STDERR สำหรับการโทรที่มีอยู่ทั้งหมดไปยัง NSLog สิ่งที่ดีเกี่ยวกับเรื่องนี้คือคุณยังสามารถตรวจสอบข้อความบันทึกของคุณสำหรับแอพที่ปรับใช้กับผู้ทดสอบและแอพที่ปรับใช้ใน App Store โดยไม่มีบันทึกที่ปรากฏในบันทึกระบบของผู้ใช้ สุดยอดของทั้งสองโลก


หนึ่งควรพิจารณาค่าใช้จ่ายที่ TestFlight เพิ่มไปยังแอปพลิเคชัน เป็นไปได้หรือไม่ที่จะเพิ่มเฉพาะส่วนการบันทึกของ TestFlight?
Johan Karlsson
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.