aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Source/SPLogger.h39
-rw-r--r--Source/SPLogger.m143
-rw-r--r--sequel-pro.xcodeproj/project.pbxproj14
3 files changed, 196 insertions, 0 deletions
diff --git a/Source/SPLogger.h b/Source/SPLogger.h
new file mode 100644
index 00000000..168f70b7
--- /dev/null
+++ b/Source/SPLogger.h
@@ -0,0 +1,39 @@
+//
+// $Id$
+//
+// SPLogger.h
+// sequel-pro
+//
+// Created by Rowan Beentje on 17/06/2009.
+// Copyright 2009 Rowan Beentje. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// More info at <http://code.google.com/p/sequel-pro/>
+
+#import <Cocoa/Cocoa.h>
+
+
+@interface SPLogger : NSObject {
+ BOOL initializedSuccessfully;
+ NSFileHandle *logFileHandle;
+}
+
++ (SPLogger *)logger;
+
+- (void) outputTimeString;
+- (void) log:(NSString *)theString, ...;
+
+@end
diff --git a/Source/SPLogger.m b/Source/SPLogger.m
new file mode 100644
index 00000000..8c65f245
--- /dev/null
+++ b/Source/SPLogger.m
@@ -0,0 +1,143 @@
+//
+// $Id$
+//
+// SPLogger.m
+// sequel-pro
+//
+// Created by Rowan Beentje on 17/06/2009.
+// Copyright 2009 Rowan Beentje. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// More info at <http://code.google.com/p/sequel-pro/>
+
+#import "SPLogger.h"
+
+static SPLogger *logger = nil;
+
+/**
+ * This is a small class intended to aid in user issue debugging; by including
+ * the header file, and using [[SPLogger logger] log:@"String with format", ...]
+ * a file will be created on the user's desktop including timestamps and
+ * the log message.
+ * This allows use of fine-grained and detailed logging, without asking the user
+ * to copy text from a console log via NSLog.
+ * As each log line must by synched to disk as soon as it is received, for safety,
+ * this class can add a performance hit when lots of logging is used.
+ */
+
+@implementation SPLogger
+
+/*
+ * Returns the shared logger object.
+ */
++ (SPLogger *)logger
+{
+ @synchronized(self) {
+ if (logger == nil) {
+ [[self alloc] init];
+ }
+ }
+
+ return logger;
+}
+
+#pragma mark -
+#pragma mark Initialisation and teardown
+
++ (id)allocWithZone:(NSZone *)zone
+{
+ @synchronized(self) {
+ if (logger == nil) {
+ logger = [super allocWithZone:zone];
+
+ return logger;
+ }
+ }
+
+ return nil;
+}
+
+- (id)init
+{
+ if ((self = [super init])) {
+ NSArray *paths = NSSearchPathForDirectoriesInDomains (NSDesktopDirectory, NSUserDomainMask, YES);
+ NSString *logFilePath = [NSString stringWithFormat:@"%@/Sequel Pro Debug Log.txt", [paths objectAtIndex:0]];
+
+ initializedSuccessfully = YES;
+
+ // Check if the debug file exists, and is writable
+ if ( [[NSFileManager defaultManager] fileExistsAtPath:logFilePath] ) {
+ if ( ![[NSFileManager defaultManager] isWritableFileAtPath:logFilePath] ) {
+ initializedSuccessfully = NO;
+ NSRunAlertPanel(@"Logging error", @"Log file exists but is not writeable; no debug log will be generated!", @"OK", nil, nil);
+ }
+
+ // Otherwise try creating one
+ } else {
+ if ( ![[NSFileManager defaultManager] createFileAtPath:logFilePath contents:[NSData data] attributes:nil] ) {
+ initializedSuccessfully = NO;
+ NSRunAlertPanel(@"Logging error", @"Could not create log file for writing; no debug log will be generated!", @"OK", nil, nil);
+ }
+ }
+
+ // Get a file handle to the file if possible
+ if (initializedSuccessfully) {
+ logFileHandle = [NSFileHandle fileHandleForWritingAtPath:logFilePath];
+ if (!logFileHandle) {
+ initializedSuccessfully = NO;
+ NSRunAlertPanel(@"Logging error", @"Could not open log file for writing; no debug log will be generated!", @"OK", nil, nil);
+ } else {
+ [logFileHandle retain];
+ [logFileHandle seekToEndOfFile];
+ NSString *bundleName = [[NSFileManager defaultManager] displayNameAtPath:[[NSBundle mainBundle] bundlePath]];
+ NSMutableString *logStart = [NSMutableString stringWithString:@"\n\n\n==========================================================================\n\n"];
+ [logStart appendString:[NSString stringWithFormat:@"%@ (r%i)\n", bundleName, [[[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"] intValue]]];
+ [logFileHandle writeData:[logStart dataUsingEncoding:NSUTF8StringEncoding]];
+ }
+ }
+ }
+
+ return self;
+}
+
+#pragma mark -
+#pragma mark Logging functions
+
+- (void) log:(NSString *)theString, ...
+{
+ if (!initializedSuccessfully) return;
+
+ // Extract any supplied arguments and build the formatted log string
+ va_list arguments;
+ va_start(arguments, theString);
+ NSString *logString = [[NSString alloc] initWithFormat:theString arguments:arguments];
+ va_end(arguments);
+
+ // Write the log line, forcing an immediate write to disk to ensure logging
+ [logFileHandle writeData:[[NSString stringWithFormat:@"%@ %@\n", [[NSDate date] descriptionWithCalendarFormat:@"%H:%M:%S" timeZone:nil locale:[[NSUserDefaults standardUserDefaults] dictionaryRepresentation]], logString] dataUsingEncoding:NSUTF8StringEncoding]];
+ [logFileHandle synchronizeFile];
+
+ [logString release];
+}
+
+- (void) outputTimeString
+{
+ if (!initializedSuccessfully) return;
+
+ [logFileHandle writeData:[[NSString stringWithFormat:@"Launched at %@\n\n", [[NSDate date] description]] dataUsingEncoding:NSUTF8StringEncoding]];
+}
+
+@end
diff --git a/sequel-pro.xcodeproj/project.pbxproj b/sequel-pro.xcodeproj/project.pbxproj
index c3ab1a7d..3ef0efb7 100644
--- a/sequel-pro.xcodeproj/project.pbxproj
+++ b/sequel-pro.xcodeproj/project.pbxproj
@@ -158,6 +158,7 @@
58D2E22E101222870063EF1D /* link-arrow-clicked.png in Resources */ = {isa = PBXBuildFile; fileRef = 58D2E22B101222870063EF1D /* link-arrow-clicked.png */; };
58D2E22F101222870063EF1D /* link-arrow-highlighted-clicked.png in Resources */ = {isa = PBXBuildFile; fileRef = 58D2E22C101222870063EF1D /* link-arrow-highlighted-clicked.png */; };
58D2E230101222870063EF1D /* link-arrow.png in Resources */ = {isa = PBXBuildFile; fileRef = 58D2E22D101222870063EF1D /* link-arrow.png */; };
+ 58DA8863103E15B5000B98DF /* SPLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 58DA8862103E15B5000B98DF /* SPLogger.m */; };
58FEF16D0F23D66600518E8E /* SPSQLParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 58FEF16C0F23D66600518E8E /* SPSQLParser.m */; };
58FEF57E0F3B4E9700518E8E /* SPTableData.m in Sources */ = {isa = PBXBuildFile; fileRef = 58FEF57D0F3B4E9700518E8E /* SPTableData.m */; };
8D15AC340486D014006FF6A4 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A7FEA54F5311CA2CBB /* Cocoa.framework */; };
@@ -520,6 +521,8 @@
58D2E22B101222870063EF1D /* link-arrow-clicked.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "link-arrow-clicked.png"; sourceTree = "<group>"; };
58D2E22C101222870063EF1D /* link-arrow-highlighted-clicked.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "link-arrow-highlighted-clicked.png"; sourceTree = "<group>"; };
58D2E22D101222870063EF1D /* link-arrow.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "link-arrow.png"; sourceTree = "<group>"; };
+ 58DA8861103E15B5000B98DF /* SPLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SPLogger.h; sourceTree = "<group>"; };
+ 58DA8862103E15B5000B98DF /* SPLogger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SPLogger.m; sourceTree = "<group>"; };
58FEF16B0F23D66600518E8E /* SPSQLParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SPSQLParser.h; sourceTree = "<group>"; };
58FEF16C0F23D66600518E8E /* SPSQLParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SPSQLParser.m; sourceTree = "<group>"; };
58FEF57C0F3B4E9700518E8E /* SPTableData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SPTableData.h; sourceTree = "<group>"; };
@@ -974,6 +977,7 @@
17E641710EF01F5C001BC333 /* GUI */,
17E641720EF01F6B001BC333 /* SSHTunnel */,
B57747D60F7A8990003B34F9 /* Category Additions */,
+ 58DA884E103E1597000B98DF /* Debugging & Support */,
);
name = Other;
sourceTree = "<group>";
@@ -1183,6 +1187,15 @@
path = UnitTests;
sourceTree = "<group>";
};
+ 58DA884E103E1597000B98DF /* Debugging & Support */ = {
+ isa = PBXGroup;
+ children = (
+ 58DA8861103E15B5000B98DF /* SPLogger.h */,
+ 58DA8862103E15B5000B98DF /* SPLogger.m */,
+ );
+ name = "Debugging & Support";
+ sourceTree = "<group>";
+ };
58FEF15E0F23D60A00518E8E /* Parsing */ = {
isa = PBXGroup;
children = (
@@ -1627,6 +1640,7 @@
584192A1101E57BB0089807F /* NSMutableArray-MultipleSort.m in Sources */,
589235321020C1230011DE00 /* SPHistoryController.m in Sources */,
BCA6271C1031B9D40047E5D5 /* SPTooltip.m in Sources */,
+ 58DA8863103E15B5000B98DF /* SPLogger.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};