Index: /trunk/ippToPsps/src/Batch.c
===================================================================
--- /trunk/ippToPsps/src/Batch.c	(revision 31029)
+++ /trunk/ippToPsps/src/Batch.c	(revision 31030)
@@ -63,5 +63,5 @@
         if (this->exitCode != PS_EXIT_SUCCESS) {
 
-            psError(PS_ERR_UNKNOWN, false, "Failed, so deleting fits file");
+            this->logger->print(this->logger, MSG_ERROR, "Batch: Failed, so deleting fits file\n");
             this->fitsOut->delete(this->fitsOut);
         }
@@ -105,5 +105,5 @@
     if (file == NULL) {
 
-        psError(PS_ERR_UNKNOWN, false, "Unable to open file at %s", this->fitsInPath);
+        this->logger->print(this->logger, MSG_ERROR, "Batch: Unable to open file at %s\n", this->fitsInPath);
         return false;
     }
@@ -113,5 +113,5 @@
     while (fgets(line, 1000, file) != NULL) this->numOfInputFiles++;
 
-    printf ("Number of input files %d\n", this->numOfInputFiles);
+    this->logger->print(this->logger, MSG_INFO, "Batch: %d input files found\n", this->numOfInputFiles);
 
     if (this->numOfInputFiles < 1) return false;
@@ -156,5 +156,5 @@
     if (!this->pmconfig) {
 
-        psError(PS_ERR_UNKNOWN, false, "Unable to read configuration.");
+        this->logger->print(this->logger, MSG_ERROR, "Batch: Unable to read configuration\n");
         this->exitCode = PS_EXIT_CONFIG_ERROR;
         return false;
@@ -220,5 +220,5 @@
 
     // create an InitData object and get survey ID
-    this->initData = new_InitData(configsBaseDir);
+    this->initData = new_InitData(configsBaseDir, this->logger);
     if (strlen(this->surveyType) > 0 && 
             !this->initData->getSurveyId(this->initData, this->surveyType, &this->surveyID)) {
@@ -230,5 +230,5 @@
     // create a FitsGenerator object
     strcat(configsBaseDir, configsDir);
-    this->fitsGenerator = new_FitsGenerator(configsBaseDir);
+    this->fitsGenerator = new_FitsGenerator(this->logger, configsBaseDir);
 
     // create full FITS out path
@@ -236,5 +236,5 @@
 
     // create an output FITS file
-    this->fitsOut = new_Fits(fitsOutPath);
+    this->fitsOut = new_Fits(fitsOutPath, this->logger);
     if (this->fitsOut->getFilePtr(this->fitsOut) == NULL) return false;
 
@@ -306,6 +306,7 @@
   Constructor. Takes a Batch object and initialises it.
   */
-bool new_Batch(Batch *this) {
-
+bool new_Batch(Logger* logger, Batch *this) {
+
+    this->logger = logger;
     this->surveyID = -1;
     this->resultsXmlDoc = NULL;
Index: /trunk/ippToPsps/src/Batch.h
===================================================================
--- /trunk/ippToPsps/src/Batch.h	(revision 31029)
+++ /trunk/ippToPsps/src/Batch.h	(revision 31030)
@@ -1,3 +1,3 @@
-/** @file ippToPsps.h
+/** @file Batch.h
  *
  *  @brief Batch
@@ -6,5 +6,5 @@
  *
  *  @author IfA
- *  Copyright 2009 Institute for Astronomy, University of Hawaii
+ *  Copyright 2011 Institute for Astronomy, University of Hawaii
  */
 
@@ -21,4 +21,5 @@
 #include "Fits.h"
 #include "InitData.h"
+#include "Logger.h"
 
 /**
@@ -49,4 +50,5 @@
     int exitCode;                  // ps exit code
     bool testMode;                 // test mode boolean
+    Logger* logger;                // Logger object 
 
     // methods
@@ -66,5 +68,5 @@
 
 // public functions
-bool new_Batch(Batch *this);
+bool new_Batch(Logger* logger, Batch *this);
 
 void ippToPsps_VersionPrint(void);
Index: /trunk/ippToPsps/src/DetectionBatch.c
===================================================================
--- /trunk/ippToPsps/src/DetectionBatch.c	(revision 31029)
+++ /trunk/ippToPsps/src/DetectionBatch.c	(revision 31030)
@@ -47,5 +47,5 @@
 
     // open input FITS file
-    Fits* fitsIn = existing_Fits(this->base.inputFiles[0]);
+    Fits* fitsIn = existing_Fits(this->base.inputFiles[0], this->base.logger);
     if (fitsIn->getFilePtr(fitsIn) == NULL)  return PS_EXIT_SYS_ERROR;
 
@@ -157,4 +157,9 @@
     }
 
+    this->base.logger->print(this->base.logger, MSG_INFO, 
+            "+-----------+---------+----------+----------------+--------------+--------------+\n");
+    this->base.logger->print(this->base.logger, MSG_INFO, 
+            "| Extension | Rows in | Rows out |  Duplicate IDs | Invalid Flux | Bogus det ID |\n");
+
     // loop round chips
     for (int x=startX; x<stopX; x++) {
@@ -190,5 +195,5 @@
             skylist = dvoSkyListByExternID(this->base.dvoConfig, sourceId, imageId, &image);
             if (skylist == NULL) {
-                psError(PS_ERR_IO, false,
+                this->base.logger->print(this->base.logger, MSG_ERROR, 
                         "DVO: can't find SkyList for sourceId='%d' imageId='%d' (CCD = XY%s): skipping this chip\n",
                         sourceId, imageId, ccdNumber);
@@ -205,5 +210,5 @@
             if (numDvoDetections > this->MAXDETECT ) {
 
-                psError(PS_ERR_IO, false, " Number of detections (%d) exceeds max limit (%ld)\n",
+                this->base.logger->print(this->base.logger, MSG_ERROR,"Number of detections (%d) exceeds max limit (%ld)\n",
                         numDvoDetections, this->MAXDETECT);
                 error = true;
@@ -370,7 +375,5 @@
             }
 
-            psLogMsg("ippToPsps", PS_LOG_INFO,
-                    "+-----------+---------+----------+----------------+--------------+--------------+\n"
-                    "| Extension | Rows in | Rows out |  Duplicate IDs | Invalid Flux | Bogus det ID |\n"
+            this->base.logger->print(this->base.logger, MSG_INFO,
                     "|  %s |  %5ld  |   %5d  |     %5d      |    %5d     |    %5d     |\n",
                     extensionName, nChipDetectionsIn, nChipDetectionsOut, numOfDuplicates, numInvalidFlux, numOfInvalidIppIDet);
@@ -385,5 +388,8 @@
     }
 
-    psLogMsg("ippToPsps", PS_LOG_INFO, "Total detections for this exposure = %ld\n", totalDetectionsOut);
+    this->base.logger->print(this->base.logger, MSG_INFO, 
+            "+-----------+---------+----------+----------------+--------------+--------------+\n");
+
+    this->base.logger->print(this->base.logger, MSG_INFO, "Total detections for this exposure = %ld\n", totalDetectionsOut);
 
     // free-up memory
@@ -419,5 +425,5 @@
     writeResults(this, minObjID, maxObjID, totalDetectionsOut);
 
-    psLogMsg("ippToPsps", PS_LOG_INFO, "Data written for a total of %d chips/OTAs", nOta);
+    this->base.logger->print(this->base.logger, MSG_INFO, "Data written for a total of %d chips/OTAs", nOta);
 
     if (error || nOta < 1) this->base.exitCode = PS_EXIT_DATA_ERROR;
@@ -481,5 +487,5 @@
             !haveExpName) {
 
-        printf("\n* ERROR with supplied arguments:");
+        this->base.logger->print(this->base.logger, MSG_ERROR, "Problem with supplied arguments\n");
         this->print(this);
         this->base.exitCode = PS_EXIT_CONFIG_ERROR;
@@ -493,14 +499,11 @@
   Constructor. Returns a new DetectionBatch object.
   */
-DetectionBatch* new_DetectionBatch(int *argc, char **argv) {
-
+DetectionBatch* new_DetectionBatch(Logger* logger, int *argc, char **argv) {
+
+    logger->print(logger, MSG_DEBUG, "DetectionBatch: Constructor\n");
     DetectionBatch *this = (DetectionBatch*)calloc(1, sizeof(DetectionBatch));
 
     // call base-class constructor
-    if (!new_Batch(&this->base)) {
-
-        psError(PS_ERR_IO, false, "Unable to create Batch base-class object");
-        return this;
-    }
+    new_Batch(logger, &this->base);
 
     this->MAXDETECT = 200000;
@@ -525,9 +528,11 @@
     psTimerStart("detectionbatch");
 
-    ippToPsps_VersionPrint();
+//    ippToPsps_VersionPrint();
 
     int exitCode;
 
-    DetectionBatch* detectionBatch = new_DetectionBatch(&argc, argv);
+    Logger* logger = new_Logger(NULL);
+
+    DetectionBatch* detectionBatch = new_DetectionBatch(logger, &argc, argv);
     detectionBatch->base.run(detectionBatch);
     exitCode = detectionBatch->base.exitCode;
@@ -537,5 +542,5 @@
     double secs = psTimerMark("detectionbatch");
 
-    psLogMsg("detectionbatch", 3, "detectionbatch completed %ssuccessfully, with exit code %d, in %.1f %s\n",
+    logger->print(logger, MSG_INFO, "detectionbatch completed %ssuccessfully, with exit code %d, in %.1f %s\n",
             (exitCode == PS_EXIT_SUCCESS) ? "" : "un",
             exitCode,
@@ -546,4 +551,5 @@
     psTimerStop();
     psLibFinalize();
+    logger->destroy(logger);
 
     return exitCode;
Index: /trunk/ippToPsps/src/DetectionBatch.h
===================================================================
--- /trunk/ippToPsps/src/DetectionBatch.h	(revision 31029)
+++ /trunk/ippToPsps/src/DetectionBatch.h	(revision 31030)
@@ -31,5 +31,5 @@
 } DetectionBatch;
 
-DetectionBatch *new_DetectionBatch(int *argc, char **argv);
+DetectionBatch *new_DetectionBatch(Logger* logger, int *argc, char **argv);
 
 # endif // IPPTOPSPS_DETECTIONBATCH_H 
Index: /trunk/ippToPsps/src/Fits.c
===================================================================
--- /trunk/ippToPsps/src/Fits.c	(revision 31029)
+++ /trunk/ippToPsps/src/Fits.c	(revision 31030)
@@ -26,5 +26,5 @@
     if (!strncmp(typename, "TSTRING", 7)) return TSTRING;
 
-    psError(PS_ERR_IO, false, "* Fits: Don't understand data type '%s'", typename);
+//    this->logger->print(this->logger, MSG_ERROR, "Fits: Don't understand data type '%s'", typename);
 
     return 0;
@@ -36,12 +36,16 @@
 static void destroy(Fits* this) {
 
+    this->logger->print(this->logger, MSG_DEBUG, "Fits: Destructor\n");
+
     int status = 0;
     if (fits_close_file(this->file, &status)) {
 
-        psError(PS_ERR_IO, false, "* Fits: Unable to close FITS file");
+        this->logger->print(this->logger, MSG_ERROR, "Fits: Unable to close FITS file '%s'\n", this->path);
         fits_report_error(stderr, status);
     }
     else 
-        psLogMsg("ippToPsps", PS_LOG_INFO, "* Fits: Closed '%s'", this->path);
+        this->logger->print(this->logger, MSG_INFO, "Fits: Closed FITS file '%s'\n", this->path);
+
+    free(this);
 }
 
@@ -56,5 +60,5 @@
     if (status) {
 
-        psError(PS_ERR_IO, false, "* Fits: Could not get value for header key '%s'\n", name);
+        this->logger->print(this->logger, MSG_ERROR, "Fits: Could not get value for header key '%s' from file at '%s'\n", name, this->path);
         return false;
     }
@@ -82,5 +86,5 @@
     if (status) {
 
-        psError(PS_ERR_IO, false, "* Fits: Failed to read vector column %d row %ld", col, row);
+        this->logger->print(this->logger, MSG_ERROR, "Fits: Failed to read vector column %d row %ld\n", col, row);
         return false;
     }
@@ -98,5 +102,5 @@
     if (status) {
 
-        psError(PS_ERR_IO, false, "* Fits: Could not get column number for '%s'\n", name);
+        this->logger->print(this->logger, MSG_ERROR, "Fits: Could not get column number for '%s'\n", name);
         return false;
     }
@@ -119,5 +123,5 @@
     if (status) {
 
-        psError(PS_ERR_IO, false, "* Fits: Unable to read col '%s'", name);
+        this->logger->print(this->logger, MSG_ERROR, "Fits: Unable to read col '%s'\n", name);
         return false;
     }
@@ -127,5 +131,5 @@
     if (status) {
 
-        psError(PS_ERR_IO, false, "* Fits: Unable to read type info for '%s'", name);
+        this->logger->print(this->logger, MSG_ERROR, "Fits: Unable to read type info for '%s'\n", name);
         return false;
     }
@@ -143,5 +147,6 @@
     if (fits_movnam_hdu(this->file, type, name, 0, &status)) {
 
-        psError(PS_ERR_IO, false, "* Fits: Can't move to table extension named '%s'\n", name);
+        this->logger->print(this->logger, MSG_ERROR, "Fits: Can't move to table extension named '%s'\n", name);
+        return false;
     }
 
@@ -173,5 +178,5 @@
     if (fits_get_num_rows(this->file, count, &status)) {
 
-        psError(PS_ERR_IO, false, "* Fits: Count not count rows in this table\n");
+        this->logger->print(this->logger, MSG_ERROR, "Fits: Count not count rows in this table\n");
         return false;
     }
@@ -196,7 +201,9 @@
     if (remove(this->path) == -1) {
 
-        psError(PS_ERR_UNKNOWN, false, "* Fits: Unable to delete '%s'", this->path);
-        return false;
-    }
+        this->logger->print(this->logger, MSG_ERROR, "Fits: Unable to delete '%s'\n", this->path);
+        return false;
+    }
+
+    this->logger->print(this->logger, MSG_INFO, "Fits: Deleted FITS file at '%s'\n", this->path);
 
     return true;
@@ -228,5 +235,5 @@
     if (status) {
 
-        psError(PS_ERR_IO, false, "* Fits: Unable to delet rows using rowlist \n");
+        this->logger->print(this->logger, MSG_ERROR, "Fits: Unable to delete rows using rowlist\n");
         return false;
     }
@@ -283,11 +290,11 @@
     else {
 
-        psError(PS_ERR_IO, false, "* Fits: Don't support datatype '%d' yet\n", datatype);
-        return false;
-    }
-
-    if (status) {
-
-        psError(PS_ERR_IO, false, "* Fits: Unable to read column data from column %d\n", colnum);
+        this->logger->print(this->logger, MSG_ERROR, "Fits: Don't understand datatype '%d'\n", datatype);
+        return false;
+    }
+
+    if (status) {
+
+        this->logger->print(this->logger, MSG_ERROR, "Fits: Unable to read column data from column %d\n", colnum);
         return false;
 
@@ -331,5 +338,5 @@
     if (status) {
 
-        psError(PS_ERR_IO, false, "* Fits: Unable to write column data for column %d\n", colnum);
+        this->logger->print(this->logger, MSG_ERROR, "Fits: Unable to write column data for column %d\n", colnum);
         return false;
 
@@ -355,5 +362,5 @@
     if (status) {
 
-        psError(PS_ERR_IO,"* Fits: Unable to create table: '%s'", name);
+        this->logger->print(this->logger, MSG_ERROR, "Fits: Unable to create table: '%s'\n", name);
         return false;
     }
@@ -366,5 +373,11 @@
   Initilization common to all constructors
   */
-static void init(Fits* this) {
+static Fits* init(const char* path, Logger* logger) {
+
+    Fits* this = (Fits*)calloc(1, sizeof(Fits));
+
+    // fields
+    strcpy(this->path, path);
+    this->logger = logger;
 
     // method pointers
@@ -390,4 +403,5 @@
     assert(this);
 
+    return this;
 }
 
@@ -398,18 +412,16 @@
 
 */
-Fits* existing_Fits(char* path) {
-
-    Fits* this = (Fits*)calloc(1, sizeof(Fits));
-
-    int status = 0;
-    strcpy(this->path, path);
-
-    if (fits_open_file(&this->file, this->path, READONLY, &status)) {
-
-        psError(PS_ERR_IO, false, "* Fits: Unable to open FITS file here %s\n", path);
+Fits* existing_Fits(const char* path, Logger* logger) {
+
+    Fits* this = init(path, logger);
+    this->logger->print(this->logger, MSG_DEBUG, "Fits: Constructor for existing file at '%s'\n", path);
+
+    int status = 0;
+    if (fits_open_file(&this->file, path, READONLY, &status)) {
+
+        this->logger->print(this->logger, MSG_ERROR, "Fits: Unable to open FITS file here %s\n", path);
         this->file = NULL;
     }
 
-    init(this);
 
     return this;
@@ -421,19 +433,16 @@
   Returns a new Fits object representing a new FITS file.
   */
-Fits* new_Fits(char* path) {
-
-    Fits* this = (Fits*)calloc(1, sizeof(Fits));
-
-    int status = 0;
-    strcpy(this->path, path);
-
-    if (fits_create_file(&this->file, this->path, &status)) {
-
-        psError(PS_ERR_IO, false, "* Fits: Unable to create file here '%s'", path);
+Fits* new_Fits(const char* path, Logger* logger) {
+
+    Fits* this = init(path, logger);
+    this->logger->print(this->logger, MSG_DEBUG, "Fits: Constructor for new file at '%s'\n", path);
+
+    int status = 0;
+    if (fits_create_file(&this->file, path, &status)) {
+
+        this->logger->print(this->logger, MSG_ERROR, "Fits: Unable to create FITS file here '%s'\n", path);
         this->file = NULL;
     }
 
-    init(this);
-
     return this;
 }
Index: /trunk/ippToPsps/src/Fits.h
===================================================================
--- /trunk/ippToPsps/src/Fits.h	(revision 31029)
+++ /trunk/ippToPsps/src/Fits.h	(revision 31030)
@@ -14,4 +14,6 @@
 #include <psmodules.h>
 
+#include "Logger.h"
+
 /**
 
@@ -24,4 +26,5 @@
     fitsfile* file;             // cfitsio file pointer
     char path[1000];            // FITS path
+    Logger* logger;             // logger object
 
     // accessor methods
@@ -53,6 +56,6 @@
 
 // constructors
-Fits* existing_Fits(char* path);
-Fits* new_Fits(char* path);
+Fits* existing_Fits(const char* path, Logger* logger);
+Fits* new_Fits(const char* path, Logger* logger);
 
 // non-class methods
Index: /trunk/ippToPsps/src/FitsGenerator.c
===================================================================
--- /trunk/ippToPsps/src/FitsGenerator.c	(revision 31029)
+++ /trunk/ippToPsps/src/FitsGenerator.c	(revision 31030)
@@ -17,5 +17,5 @@
   Finds a column within this table
   */
-static Column* findColumn(Table* table, const char* name) {
+static Column* findColumn(FitsGenerator* this, Table* table, const char* name) {
 
     Column* column = NULL;
@@ -29,5 +29,5 @@
     }
 
-    if (!column) psError(PS_ERR_IO, false, "Could not find column '%s' in table '%s'", name, table->name);
+    if (!column) this->logger->print(this->logger, MSG_ERROR, "Could not find column '%s' in table '%s'\n", name, table->name);
 
     return column;
@@ -49,5 +49,5 @@
     }
 
-    if (!table) psError(PS_ERR_IO, false, "Could not find table '%s'", name);
+    if (!table) this->logger->print(this->logger, MSG_ERROR, "Could not find table '%s'\n", name);
 
     return table;
@@ -214,8 +214,8 @@
    opens an XML file and returns the document
    */
-static xmlDoc* openXmlFile(const char* path) {
+static xmlDoc* openXmlFile(FitsGenerator* this, const char* path) {
 
     xmlDoc* doc = xmlReadFile(path, NULL, 0);
-    if (doc == NULL) psError(PS_ERR_IO, false, "Unable to open XML file at %s", path);
+    if (doc == NULL) this->logger->print(this->logger, MSG_ERROR, "Unable to open XML file at %s\n", path);
     return doc;
 }
@@ -235,5 +235,5 @@
   Populates the provided table with data from XML
   */
-static bool populateTable(Table* table, xmlNode* rootElement, Fits *fitsOut) {
+static bool populateTable(FitsGenerator* this, Table* table, xmlNode* rootElement, Fits *fitsOut) {
 
     char tempStr[100];
@@ -253,5 +253,5 @@
     if(!tableNode) {
 
-        psError(PS_ERR_IO,"Could not find table: %s", table->name);
+        this->logger->print(this->logger, MSG_ERROR, "Could not find table: %s\n", table->name);
         return false;
     }
@@ -320,5 +320,5 @@
 
             }
-            if (status) psError(PS_ERR_IO, false, "Unable to write value of %s to column %s in table %s", 
+            if (status) this->logger->print(this->logger, MSG_ERROR, "Unable to write value of %s to column %s in table %s\n", 
                     tempStr, table->columns[i].pspsName, table->name);
         }
@@ -339,5 +339,5 @@
   Loads a table description from XML
   */
-static bool loadTableDescription(Table* table, xmlNode* tableNode) {
+static bool loadTableDescription(FitsGenerator* this, Table* table, xmlNode* tableNode) {
 
     bool ret = true;
@@ -391,10 +391,10 @@
     if (columnNum < 1) {
 
-        psError(PS_ERR_IO, false, "Found no columns for table '%s'", tableName);
+        this->logger->print(this->logger, MSG_ERROR, "Found no columns for table '%s'\n", tableName);
         ret = false;
     }
 
     if (columnNum != table->numOfColumns)
-        psError(PS_ERR_IO, false, "Mismatch between number of columns expected (%d) and those found (%d)", table->numOfColumns, columnNum);
+        this->logger->print(this->logger, MSG_ERROR, "Mismatch between number of columns expected (%d) and those found (%d)\n", table->numOfColumns, columnNum);
 
     return ret;
@@ -411,5 +411,5 @@
     psStringAppend(&path, "%s/tables.xml", this->configsPath);
 
-    xmlDoc* doc = openXmlFile(path);
+    xmlDoc* doc = openXmlFile(this, path);
 
     if (doc == NULL) {
@@ -424,5 +424,5 @@
     if (strcmp((const char*)rootElement->name, "tableDescriptions")!=0) {
 
-        psError(PS_ERR_IO, false, "Root node of XML is not 'tableDescriptions', as it should be");
+        this->logger->print(this->logger, MSG_ERROR, "Root node of XML is not 'tableDescriptions', as it should be\n");
         return false;
     }
@@ -445,5 +445,5 @@
                 table = this->tables+tableNum;
 
-                if (!loadTableDescription(table, node)) ret = false;
+                if (!loadTableDescription(this, table, node)) ret = false;
                 else tableNum++;
             }
@@ -452,5 +452,5 @@
 
     if (tableNum != this->numOfTables)
-        psError(PS_ERR_IO, false, "Mismatch between number of tables expected (%d) and those found (%d)", this->numOfTables, tableNum);
+        this->logger->print(this->logger, MSG_ERROR, "Mismatch between number of tables expected (%d) and those found (%d)\n", this->numOfTables, tableNum);
 
     closeXmlFile(doc);
@@ -486,5 +486,5 @@
                 // column type
                 getAttribute(node, "pspsName", buffer);
-                column = findColumn(table, buffer);
+                column = findColumn(this, table, buffer);
 
                 if (!column) continue;
@@ -518,5 +518,5 @@
     psStringAppend(&path, "%s/map.xml", this->configsPath);
 
-    xmlDoc* doc = openXmlFile(path);
+    xmlDoc* doc = openXmlFile(this, path);
 
     if (doc == NULL) {
@@ -529,5 +529,5 @@
 
     if (strcmp((const char*)rootElement->name, "tabledata")!=0) {
-        psError(PS_ERR_IO, false, "Root node of XML is not 'tabledata', as it should be");
+        this->logger->print(this->logger, MSG_ERROR, "Root node of XML is not 'tabledata', as it should be\n");
         return false;
     }
@@ -560,5 +560,5 @@
     psStringAppend(&path, "%s/data.xml", this->configsPath);
 
-    xmlDoc* doc = openXmlFile(path);
+    xmlDoc* doc = openXmlFile(this, path);
 
     if (doc == NULL) {
@@ -571,10 +571,10 @@
 
     if (strcmp((const char*)rootElement->name, "tabledata")!=0) {
-        psError(PS_ERR_IO, false, "Root node of XML is not 'tabledata', as it should be");
+        this->logger->print(this->logger, MSG_ERROR, "Root node of XML is not 'tabledata', as it should be\n");
         return false;
     }
 
     for (uint32_t i=0; i<this->numOfTables; i++) {
-        if (!populateTable(this->tables+i, rootElement, fitsOut)) {
+        if (!populateTable(this, this->tables+i, rootElement, fitsOut)) {
             ret = false;
         }
@@ -590,4 +590,5 @@
   */
 static bool populateTableFromFits(
+        FitsGenerator* this,
         Table* table,
         Fits *fitsIn, 
@@ -678,5 +679,5 @@
 
                 default:
-                    psError(PS_ERR_IO, false, "Don't know IPP type (%d) for mapping from  '%d'  '%s' to '%s'", table->columns[i].ippType,
+                    this->logger->print(this->logger, MSG_ERROR, "Don't know IPP type (%d) for mapping from  '%d'  '%s' to '%s'\n", table->columns[i].ippType,
                             table->columns[i].ippColNum, table->columns[i].ippName, table->columns[i].pspsName);
                     break;
@@ -711,5 +712,5 @@
 
     if(!createTable(table, fitsOut, nRows)) return false;
-    return populateTableFromFits(table, fitsIn, fitsOut, nRows, fromHeader);
+    return populateTableFromFits(this, table, fitsIn, fitsOut, nRows, fromHeader);
 }
 
@@ -733,5 +734,5 @@
   Constructor.
   */
-FitsGenerator* new_FitsGenerator(const char* path) {
+FitsGenerator* new_FitsGenerator(Logger* logger, const char* path) {
 
     FitsGenerator* this = (FitsGenerator*)calloc(1, sizeof(FitsGenerator));
@@ -739,4 +740,5 @@
     this->configsPath = NULL;
     psStringAppend(&this->configsPath, path);
+    this->logger = logger;
 
     // method pointers
Index: /trunk/ippToPsps/src/FitsGenerator.h
===================================================================
--- /trunk/ippToPsps/src/FitsGenerator.h	(revision 31029)
+++ /trunk/ippToPsps/src/FitsGenerator.h	(revision 31030)
@@ -13,4 +13,6 @@
 
 #include <psmodules.h>
+
+#include "Logger.h"
 
 // column class
@@ -53,4 +55,5 @@
     Table* tables;
     int numOfTables;
+    Logger* logger;
 
     // methods
@@ -64,5 +67,5 @@
 
 // constructor
-FitsGenerator* new_FitsGenerator(const char* path);
+FitsGenerator* new_FitsGenerator(Logger* logger, const char* path);
 
 #endif // IPPTOPSPS_FITSGENERATOR_H
Index: /trunk/ippToPsps/src/InitBatch.c
===================================================================
--- /trunk/ippToPsps/src/InitBatch.c	(revision 31029)
+++ /trunk/ippToPsps/src/InitBatch.c	(revision 31030)
@@ -57,14 +57,11 @@
   Constructor
   */
-InitBatch* new_InitBatch(int *argc, char **argv) {
+InitBatch* new_InitBatch(Logger* logger, int *argc, char **argv) {
 
+    logger->print(logger, MSG_DEBUG, "InitBatch: Constructor\n");
     InitBatch *this = (InitBatch*)calloc(1, sizeof(InitBatch));
 
     // call base-class constructor
-    if (!new_Batch(&this->base)) {
-
-        psError(PS_ERR_IO, false, "Unable to create Batch base-class object");
-        return this;
-    }
+    new_Batch(logger, &this->base);
 
     // method pointers
@@ -85,9 +82,11 @@
     psTimerStart("initbatch");
 
-    ippToPsps_VersionPrint();
+//    ippToPsps_VersionPrint();
 
     int exitCode;
 
-    InitBatch* initBatch = new_InitBatch(&argc, argv);
+    Logger* logger = new_Logger(NULL);
+
+    InitBatch* initBatch = new_InitBatch(logger, &argc, argv);
     initBatch->base.run(initBatch);
     exitCode = initBatch->base.exitCode;
@@ -97,5 +96,5 @@
     double secs = psTimerMark("initbatch");
 
-    psLogMsg("initbatch", 3, "initbatch completed %ssuccessfully, with exit code %d, in %.1f %s\n",
+    logger->print(logger, MSG_INFO, "initbatch completed %ssuccessfully, with exit code %d, in %.1f %s\n",
             (exitCode == PS_EXIT_SUCCESS) ? "" : "un",
             exitCode,
@@ -106,4 +105,5 @@
     psTimerStop();
     psLibFinalize();
+    logger->destroy(logger);
 
     return exitCode;
Index: /trunk/ippToPsps/src/InitBatch.h
===================================================================
--- /trunk/ippToPsps/src/InitBatch.h	(revision 31029)
+++ /trunk/ippToPsps/src/InitBatch.h	(revision 31030)
@@ -31,5 +31,5 @@
 
 // constructor
-InitBatch *new_InitBatch(int *argc, char **argv);
+InitBatch *new_InitBatch(Logger *logger, int *argc, char **argv);
 
 # endif // IPPTOPSPS_INITBATCH_H 
Index: /trunk/ippToPsps/src/InitData.c
===================================================================
--- /trunk/ippToPsps/src/InitData.c	(revision 31029)
+++ /trunk/ippToPsps/src/InitData.c	(revision 31030)
@@ -28,4 +28,5 @@
   */
 static bool getRowAttribute(
+        InitData* this, 
         xmlNode* tableNode,
         const char* keyName, 
@@ -58,7 +59,6 @@
     }
 
-    psError(PS_ERR_UNKNOWN, 
-            false, 
-            "* InitData: Could not find value for '%s' for '%s' with value '%s'", 
+    this->logger->print(this->logger, MSG_ERROR, 
+            "InitData: Could not find value for '%s' for '%s' with value '%s'\n", 
             attName, keyName, keyValue);
 
@@ -83,5 +83,6 @@
 
     if (strcmp((const char*)rootElement->name, "tabledata")!=0) {
-        psError(PS_ERR_IO, false, "* InitData: Root node of XML is not 'tabledata', as it should be");
+        this->logger->print(this->logger, MSG_ERROR, 
+                "InitData: Root node of XML is not 'tabledata', as it should be\n");
         return false;
     }
@@ -98,5 +99,5 @@
             if (strcmp(tempStr, tableName)!=0) continue;
 
-            ret = getRowAttribute(node, keyName, keyValue, attName, attValue);
+            ret = getRowAttribute(this, node, keyName, keyValue, attName, attValue);
             break;
         }
@@ -155,5 +156,5 @@
     }
 
-    psLogMsg("ippToPsps", PS_LOG_INFO, "* InitData: destructor");
+    this->logger->print(this->logger, MSG_DEBUG, "InitData: destructor\n");
 
     free(this);
@@ -163,14 +164,18 @@
   Constructor.
   */
-InitData* new_InitData(const char* path) {
+InitData* new_InitData(const char* path, Logger* logger) {
 
-    psLogMsg("ippToPsps", PS_LOG_INFO, "* InitData: constructor");
+
 
     InitData* this = (InitData*)calloc(1, sizeof(InitData));
+    this->logger = logger;
+
+    this->logger->print(this->logger, MSG_DEBUG, "InitData: Constructor\n");
 
     sprintf(this->path, "%s/init/data.xml", path);
 
     this->doc = xmlReadFile(this->path, NULL, 0);
-    if (this->doc == NULL) psError(PS_ERR_IO, false, "* InitData: Unable to open XML file at %s", this->path);
+    this->logger->print(this->logger, MSG_ERROR, 
+            "InitData: Unable to open XML file at %s\n", this->path);
 
     // method pointers
Index: /trunk/ippToPsps/src/InitData.h
===================================================================
--- /trunk/ippToPsps/src/InitData.h	(revision 31029)
+++ /trunk/ippToPsps/src/InitData.h	(revision 31030)
@@ -17,4 +17,6 @@
 #include <psmodules.h>
 
+#include "Logger.h"
+
 /**
 
@@ -27,4 +29,5 @@
     char path[1000];
     xmlDoc* doc;
+    Logger* logger;
 
     // methods
@@ -38,5 +41,5 @@
 
 // constructor
-InitData* new_InitData(const char* path);
+InitData* new_InitData(const char* path, Logger* logger);
 
 #endif // IPPTOPSPS_INITDATA_H
Index: /trunk/ippToPsps/src/Logger.c
===================================================================
--- /trunk/ippToPsps/src/Logger.c	(revision 31030)
+++ /trunk/ippToPsps/src/Logger.c	(revision 31030)
@@ -0,0 +1,98 @@
+/** @file Logger.c
+ *
+ *  @ingroup ippToPsps
+ *
+ *  Source for all methods in the Logger class
+ *
+ *  @author IfA
+ *  Copyright 2011 Institute for Astronomy, University of Hawaii
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <time.h>
+
+#include "Logger.h"
+
+/**
+  Destructor
+  */
+static void destroy(Logger* this) {
+
+    this->print(this, MSG_DEBUG, "Logger: Destructor\n");
+    free(this);
+}
+
+/**
+  Prints a message
+  */
+static void print(void* this, const int8_t typeInt, const char* fmt, ...) {
+
+    va_list args;
+    va_start(args, fmt);
+    char msg_fmt[1000];
+
+    // get message-type string
+    char typeStr[20];
+    switch(typeInt) {
+
+        case MSG_INFO:
+            sprintf(typeStr, "INFO ");
+            break;
+        case MSG_ERROR:
+            sprintf(typeStr, "ERROR");
+            break;
+        case MSG_DEBUG:
+            sprintf(typeStr, "DEBUG");
+            break;
+        default:
+            break;
+    }
+
+    // get time string
+    char timeStr[30];
+    time_t now = time(NULL);
+    struct tm tim = *(localtime(&now));
+    strftime(timeStr, 30, "%Y/%m/%d %H:%M:%S",&tim);
+
+    if (typeInt == MSG_NONE)
+        sprintf(msg_fmt, "%s", fmt);
+    else
+        sprintf(msg_fmt, "%s | %s | %s", timeStr, typeStr, fmt);
+
+    Logger* logger = (Logger*)this;
+
+    // write either to file or stdout
+    if(logger->file == NULL) vprintf(msg_fmt, args);
+    else vfprintf(logger->file, msg_fmt, args);
+}
+
+/**
+  Constructor. 
+
+  Returns a new Logger object.
+  */
+Logger* new_Logger(const char* path) {
+
+    Logger* this = (Logger*)calloc(1, sizeof(Logger));
+
+    this->file = NULL;
+
+    // open a file to write to
+    if (path != NULL) {
+
+        this->file = fopen(path, "w+");
+        if (this->file == NULL) 
+            print(this, MSG_ERROR, "Logger: cannot open file for writing here '%s'\n", path);
+    }
+
+    print(this, MSG_DEBUG, "Logger: Constructor\n");
+
+    // method pointers
+    this->print = print;
+    this->destroy = destroy;
+
+    return this;
+}
+
Index: /trunk/ippToPsps/src/Logger.h
===================================================================
--- /trunk/ippToPsps/src/Logger.h	(revision 31030)
+++ /trunk/ippToPsps/src/Logger.h	(revision 31030)
@@ -0,0 +1,47 @@
+/** @file logger.h
+ *
+ *  @brief Batch
+ *
+ *  @ingroup ippToPsps
+ *
+ *  @author IfA
+ *  Copyright 2011 Institute for Astronomy, University of Hawaii
+ */
+
+#ifndef IPPTOPSPS_LOGGER_H
+#define IPPTOPSPS_LOGGER_H
+
+typedef enum {
+
+    MSG_INFO,
+    MSG_ERROR,
+    MSG_DEBUG,
+    MSG_NONE
+
+} MessageTypes;
+
+
+/**
+  Logger class.
+
+  Prints either to stdout or a file
+  */
+typedef struct Logger {
+
+    // fields
+    FILE* file;
+
+    // methods
+    void (*print)(void* logger, const int8_t typeInt, const char* fmt, ...);
+
+    // destructor
+    void (*destroy)();
+
+
+} Logger;
+
+// constructor
+Logger* new_Logger(const char* path);
+
+# endif // IPPTOPSPS_LOGGER_H 
+
Index: /trunk/ippToPsps/src/Makefile.am
===================================================================
--- /trunk/ippToPsps/src/Makefile.am	(revision 31029)
+++ /trunk/ippToPsps/src/Makefile.am	(revision 31030)
@@ -33,4 +33,5 @@
 	Fits.c \
 	InitData.c \
+	Logger.c \
 	FitsGenerator.c
 
@@ -44,4 +45,5 @@
 	Fits.c \
 	InitData.c \
+	Logger.c \
 	FitsGenerator.c
 
@@ -55,4 +57,5 @@
 	Fits.c \
 	InitData.c \
+	Logger.c \
 	FitsGenerator.c
 
Index: /trunk/ippToPsps/src/StackBatch.c
===================================================================
--- /trunk/ippToPsps/src/StackBatch.c	(revision 31029)
+++ /trunk/ippToPsps/src/StackBatch.c	(revision 31030)
@@ -62,4 +62,9 @@
     long unmatched = 0, totalDetections = 0, numOfDuplicates = 0, numInvalidFlux = 0, numDetectionsOut = 0;
 
+    this->base.logger->print(this->base.logger, MSG_INFO,
+            "+---------------+---------+----------+------------------+---------------+--------------+\n");
+    this->base.logger->print(this->base.logger, MSG_INFO,
+            "|   Extension   | Rows in | Rows out | Missing from DVO | Duplicate IDs | Invalid Flux |\n");
+
     for (long s=0; s<nDet; s++) {
 
@@ -102,9 +107,10 @@
 
     }
-    psLogMsg("ippToPsps", PS_LOG_INFO,
-            "+---------------+---------+----------+------------------+---------------+--------------+\n"
-            "|   Extension   | Rows in | Rows out | Missing from DVO | Duplicate IDs | Invalid Flux |\n"
+
+    this->base.logger->print(this->base.logger, MSG_INFO,
             "|  %12s |  %5ld  |   %5ld  |      %5ld       |    %5ld      |    %5ld     |\n",
             extensionName, nDet, numDetectionsOut, unmatched, numOfDuplicates, numInvalidFlux);
+    this->base.logger->print(this->base.logger, MSG_INFO,
+            "+---------------+---------+----------+------------------+---------------+--------------+\n");
 
 
@@ -315,5 +321,5 @@
 
     // open input FITS file
-    Fits* fitsIn = existing_Fits(this->base.inputFiles[0]);
+    Fits* fitsIn = existing_Fits(this->base.inputFiles[0], this->base.logger);
     if (fitsIn->getFilePtr(fitsIn) == NULL)  return PS_EXIT_SYS_ERROR;
 
@@ -425,14 +431,11 @@
   Constructor
   */
-StackBatch* new_StackBatch(int *argc, char **argv) {
-
+StackBatch* new_StackBatch(Logger* logger, int *argc, char **argv) {
+
+    logger->print(logger, MSG_DEBUG, "StackBatch: Constructor\n");
     StackBatch *this = (StackBatch*)calloc(1, sizeof(StackBatch));
 
     // call base-class constructor
-    if (!new_Batch(&this->base)) {
-
-        psError(PS_ERR_IO, false, "Unable to create Batch base-class object");
-        return this;
-    }
+    new_Batch(logger, &this->base);
 
     this->MAXDETECT = 150000;
@@ -455,9 +458,11 @@
     psTimerStart("stackbatch");
 
-    ippToPsps_VersionPrint();
+//    ippToPsps_VersionPrint();
 
     int exitCode;
 
-    StackBatch* stackBatch = new_StackBatch(&argc, argv);
+    Logger* logger = new_Logger(NULL);
+
+    StackBatch* stackBatch = new_StackBatch(logger, &argc, argv);
     stackBatch->base.run(stackBatch);
     exitCode = stackBatch->base.exitCode;
@@ -467,5 +472,5 @@
     double secs = psTimerMark("stackbatch");
 
-    psLogMsg("stackbatch", 3, "stackbatch completed %ssuccessfully, with exit code %d, in %.1f %s\n",
+    logger->print(logger, MSG_INFO, "stackbatch completed %ssuccessfully, with exit code %d, in %.1f %s\n",
             (exitCode == PS_EXIT_SUCCESS) ? "" : "un",
             exitCode,
@@ -476,4 +481,5 @@
     psTimerStop();
     psLibFinalize();
+    logger->destroy(logger);
 
     return exitCode;
Index: /trunk/ippToPsps/src/StackBatch.h
===================================================================
--- /trunk/ippToPsps/src/StackBatch.h	(revision 31029)
+++ /trunk/ippToPsps/src/StackBatch.h	(revision 31030)
@@ -30,5 +30,5 @@
 } StackBatch;
 
-StackBatch *new_StackBatch(int *argc, char **argv);
+StackBatch *new_StackBatch(Logger* logger, int *argc, char **argv);
 
 # endif // IPPTOPSPS_STACKBATCH_H 
