public static void writeInstances(
      List<? extends Instance<AttributesMap, Serializable>> instances, String filePath) {
    List<String[]> allRows = Lists.newLinkedList();
    String[] header = getHeader(instances);
    allRows.add(header);
    for (Instance<AttributesMap, Serializable> instance : instances) {
      allRows.add(instanceToRow(instance, header));
    }
    File file = new File(filePath);
    Writer writer = null;
    try {
      writer = new BufferedWriter(new FileWriter(file));
      CSVWriter csvWriter = new CSVWriter(writer);
      csvWriter.writeAll(allRows);
      writer.close();

    } catch (IOException e) {
      e.printStackTrace();
      System.exit(1);
    }
  }
  /** {@inheritDoc} */
  @Override
  public void onDataWriterException(final DataWriterException e) {
    CSVWriter writer = null;
    if (e.getErrorId().equalsIgnoreCase("SINGLE_ROW")) {
      try {
        String path =
            GAPageViewDataExceptionHandler.getErrorFilePath(
                e.getTableDefinition().getProperty("relativePath"),
                e.getTableDefinition().getProperty("startDate"));
        File file = FileSystem.getDefault().getFile("logs/" + path, true, true);
        writer = new CSVWriter(new FileWriter(file, true));
        Map<String, Object> row = (Map<String, Object>) e.getData().get("row");
        Object[] values = row.values().toArray();
        Object[] keys = row.keySet().toArray();
        String[] stringValues = new String[values.length];
        String[] headerValue = new String[keys.length];
        for (int i = 0; i < stringValues.length; i++) {
          stringValues[i] = (values[i] != null) ? values[i].toString() : null;
          headerValue[i] = (keys[i] != null) ? keys[i].toString() : null;
        }
        if (!header) {
          writer.writeNext(headerValue);
          writer.flush();
          header = true;
        }
        String data = stringValues[stringValues.length - 1] + " " + e.getData().get("e");
        stringValues[stringValues.length - 1] = data;
        writer.writeNext(stringValues);
        writer.flush();
        writer.close();
      } catch (Exception ee) {
        logger.error(ee.getMessage());
      }
    } else if (e.getErrorId().equalsIgnoreCase("BATCH_READ")) {
      try {
        String path =
            GAPageViewDataExceptionHandler.getErrorFilePath(
                e.getTableDefinition().getProperty("relativePath"),
                e.getTableDefinition().getProperty("startDate"));
        File file = FileSystem.getDefault().getFile("logs/" + path, true, true);
        writer = new CSVWriter(new FileWriter(file, true));
        String[] row = (String[]) e.getData().get("row");
        String[] headerRow = (String[]) e.getData().get("header");
        if (!header) {
          writer.writeNext(headerRow);
          header = true;
        }

        String data = row[row.length - 1] + e.getData().get("e");
        row[row.length - 1] = data;
        writer.writeNext(row);

        writer.flush();
        writer.close();
      } catch (Exception exceptionObject) {
        logger.error(exceptionObject.getMessage());
      }
    } else if (e.getErrorId().equalsIgnoreCase("ROW_UPDATE")) {
      String[] headerValue = null;
      try {

        String path =
            GAPageViewDataExceptionHandler.getErrorFilePath(
                e.getTableDefinition().getProperty("relativePath"),
                e.getTableDefinition().getProperty("startDate"));
        File file = FileSystem.getDefault().getFile("logs/" + path, true, true);
        writer = new CSVWriter(new FileWriter(file, true));
        Collection<Map<String, Object>> batch =
            (Collection<Map<String, Object>>) e.getData().get("batch");
        super.writerFailedCount = writerFailedCount + batch.size();
        List<String[]> rows = new ArrayList<String[]>(batch.size());
        for (Map<String, Object> row : batch) {
          Object[] values = row.values().toArray();
          Object[] keys = row.keySet().toArray();
          String[] stringValues = new String[values.length];
          headerValue = new String[keys.length];

          for (int i = 0; i < stringValues.length; i++) {
            boolean exceptionFlag = false;
            stringValues[i] = (values[i] != null) ? values[i].toString() : null;
            headerValue[i] = (keys[i] != null) ? keys[i].toString() : null;
          }
          rows.add(stringValues);
        }
        if (!header) {
          writer.writeNext(headerValue);
          writer.flush();
          header = true;
        }

        writer.writeAll(rows);
        writer.flush();
        writer.close();
      } catch (Exception exceptionObject) {
        logger.error(exceptionObject.getMessage(), exceptionObject);
      }
    } else if (e.getErrorId().equalsIgnoreCase("BATCH_UPDATE")) {
      String[] headerValue = null;
      try {
        String path =
            GAPageViewDataExceptionHandler.getErrorFilePath(
                e.getTableDefinition().getProperty("relativePath"),
                e.getTableDefinition().getProperty("startDate"));
        File file = FileSystem.getDefault().getFile("logs/" + path, true, true);
        writer = new CSVWriter(new FileWriter(file, true));
        Collection<Map<String, Object>> batch =
            (Collection<Map<String, Object>>) e.getData().get("batch");
        super.writerFailedCount = writerFailedCount + batch.size();

        List<String[]> rows = new ArrayList<String[]>(batch.size());
        for (Map<String, Object> row : batch) {
          Object[] values = row.values().toArray();
          Object[] keys = row.keySet().toArray();
          String[] stringValues = new String[values.length];
          headerValue = new String[keys.length];

          for (int i = 0; i < stringValues.length; i++) {
            stringValues[i] = (values[i] != null) ? values[i].toString() : null;
            headerValue[i] = (keys[i] != null) ? keys[i].toString() : null;
          }
          rows.add(stringValues);
        }
        if (!header) {
          writer.writeNext(headerValue);
          writer.flush();
          header = true;
        }
        writer.writeAll(rows);
        writer.flush();
        writer.close();
      } catch (IOException e1) {
        logger.warn("GAEventDataExceptionHandler onDataWriterException() " + e.getMessage());
      }
    } else if (e.getErrorId().equalsIgnoreCase("ROW_DUPLICATE")) {
      String[] headerValue = null;
      try {
        String path =
            GAPageViewDataExceptionHandler.getErrorFilePath(
                e.getTableDefinition().getProperty("relativePath"),
                e.getTableDefinition().getProperty("startDate"));
        File file = FileSystem.getDefault().getFile("logs/" + path, true, true);
        writer = new CSVWriter(new FileWriter(file, true));
        Collection<Map<String, Object>> batch =
            (Collection<Map<String, Object>>) e.getData().get("batch");
        super.writerFailedCount = writerFailedCount + batch.size();

        List<String[]> rows = new ArrayList<String[]>(batch.size());
        for (Map<String, Object> row : batch) {
          Object[] values = row.values().toArray();
          Object[] keys = row.keySet().toArray();
          String[] stringValues = new String[values.length];
          headerValue = new String[keys.length];

          for (int i = 0; i < stringValues.length; i++) {
            stringValues[i] = (values[i] != null) ? values[i].toString() : null;
            headerValue[i] = (keys[i] != null) ? keys[i].toString() : null;
          }
          String data = stringValues[stringValues.length - 1] + "  " + e.getData().get("e");
          stringValues[stringValues.length - 1] = data;
          rows.add(stringValues);
        }
        if (!header) {
          writer.writeNext(headerValue);
          writer.flush();
          header = true;
        }

        writer.writeAll(rows);
        writer.flush();
        writer.close();
      } catch (IOException e1) {
        logger.warn("GAEventDataExceptionHandler onDataWriterException() " + e.getMessage());
      }
    }
    super.onDataWriterException(e, false);
  }