Here's what we do:
- Let the iPhone handle its own crash dumps through the existing App Store mechanisms. Update: having found iTunes Connect to be unreliable at providing crash reports, I recommend using Fabric/Crashlytics, or a competitor like Crittercism or Rollbar.
- Our released product has no trace in, this seems to be consistent with what most other iPhone apps do.
- If a bug is reported then we reproduce it using a traced build.
In more detail:
- We define macros to NSLog trace at numerous different levels of granularity.
- Use Xcode build settings to change the trace level, which controls how much trace gets compiled into the product, e.g. there are Release and Debug build configurations.
- If no trace level is defined then we show full trace in the Simulator, and no trace when running on a real Device.
I've included example code below showing how we've written this, and what the output looks like.
We define multiple different trace levels so developers can identify which lines of trace are important, and can filter out lower level detail if they want to.
Example code:
- (void)myMethod:(NSObject *)xiObj
{
TRC_ENTRY;
TRC_DBG(@"Boring low level stuff");
TRC_NRM(@"Higher level trace for more important info");
TRC_ALT(@"Really important trace, something bad is happening");
TRC_ERR(@"Error, this indicates a coding bug or unexpected condition");
TRC_EXIT;
}
Example trace output:
2009-09-11 14:22:48.051 MyApp[3122:207] ENTRY:+[MyClass myMethod:]
2009-09-11 14:22:48.063 MyApp[3122:207] DEBUG:+[MyClass myMethod:]:Boring low level stuff
2009-09-11 14:22:48.063 MyApp[3122:207] NORMAL:+[MyClass myMethod:]:Higher level trace for more important info
2009-09-11 14:22:48.063 MyApp[3122:207] ALERT:+[MyClass myMethod:]:Really important trace, something bad is happening
2009-09-11 14:22:48.063 MyApp[3122:207] ERROR:+[MyClass myMethod:]:Error, this indicates a coding bug or unexpected condition
2009-09-11 14:22:48.073 MyApp[3122:207] EXIT:+[MyClass myMethod:]
Our trace definitions:
#ifndef TRC_LEVEL
#if TARGET_IPHONE_SIMULATOR != 0
#define TRC_LEVEL 0
#else
#define TRC_LEVEL 5
#endif
#endif
/*****************************************************************************/
/* Entry/exit trace macros */
/*****************************************************************************/
#if TRC_LEVEL == 0
#define TRC_ENTRY NSLog(@"ENTRY: %s:%d:", __PRETTY_FUNCTION__,__LINE__);
#define TRC_EXIT NSLog(@"EXIT: %s:%d:", __PRETTY_FUNCTION__,__LINE__);
#else
#define TRC_ENTRY
#define TRC_EXIT
#endif
/*****************************************************************************/
/* Debug trace macros */
/*****************************************************************************/
#if (TRC_LEVEL <= 1)
#define TRC_DBG(A, ...) NSLog(@"DEBUG: %s:%d:%@", __PRETTY_FUNCTION__,__LINE__,[NSString stringWithFormat:A, ## __VA_ARGS__]);
#else
#define TRC_DBG(A, ...)
#endif
#if (TRC_LEVEL <= 2)
#define TRC_NRM(A, ...) NSLog(@"NORMAL:%s:%d:%@", __PRETTY_FUNCTION__,__LINE__,[NSString stringWithFormat:A, ## __VA_ARGS__]);
#else
#define TRC_NRM(A, ...)
#endif
#if (TRC_LEVEL <= 3)
#define TRC_ALT(A, ...) NSLog(@"ALERT: %s:%d:%@", __PRETTY_FUNCTION__,__LINE__,[NSString stringWithFormat:A, ## __VA_ARGS__]);
#else
#define TRC_ALT(A, ...)
#endif
#if (TRC_LEVEL <= 4)
#define TRC_ERR(A, ...) NSLog(@"ERROR: %s:%d:%@", __PRETTY_FUNCTION__,__LINE__,[NSString stringWithFormat:A, ## __VA_ARGS__]);
#else
#define TRC_ERR(A, ...)
#endif
Xcode settings:
In Xcode build settings, choose "Add User-Defined Setting" (by clicking on the little cog at the bottom left of the build configuration screen), then define a new setting called GCC_PREPROCESSOR_DEFINITIONS
and give it the value TRC_LEVEL=0
.
The only subtlety is that Xcode doesn't know to do a clean build if you change this setting, so remember to manually do a Clean if you change it.