# Copyright 2011-2014 Splunk, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"): you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from __future__ import absolute_import from numbers import Number import csv class DictWriter(csv.DictWriter, object): """ Splunk multi-value-aware CSV dictionary writer. """ def __init__(self, f, command, fieldnames=None, mv_delimiter='\n'): super(DictWriter, self).__init__( f, fieldnames, dialect='splunklib.searchcommands') self._command = command self._fieldnames = None self._mv_delimiter = mv_delimiter self._output_file = f def writeheader(self): if self._header_written(): return _fieldnames = self.fieldnames + ['__mv_' + fn for fn in self.fieldnames] save_fieldnames = self.fieldnames self.fieldnames = _fieldnames try: self._command.messages.write(self._output_file) self.writer.writerow(_fieldnames) finally: self.fieldnames = save_fieldnames self._fieldnames = _fieldnames def writerow(self, record): self._writeheader(record) self._writerow(record) def writerows(self, records): self._writeheader(records[0]) for record in records: self._writerow(record) def _encode_list(self, value): if len(value) == 0: return None, None if len(value) == 1: return value[0], None multi_value = ';'.join( ['$' + DictWriter._to_string(item).replace('$', '$$') + '$' for item in value]) value = self._mv_delimiter.join([repr(item) for item in value]) return value, multi_value def _header_written(self): return self._fieldnames is not None @staticmethod def _to_string(item): if isinstance(item, bool): return 't' if item else 'f' if isinstance(item, str): return item if isinstance(item, Number): return str(item) return repr(item) def _writeheader(self, record): if self.fieldnames is None: self.fieldnames = sorted(record.keys()) self.writeheader() def _writerow(self, record): row = {} for fieldname in self.fieldnames: value = record[fieldname] if isinstance(value, list): value, multi_value = self._encode_list(value) row[fieldname] = value row['__mv_' + fieldname] = multi_value elif isinstance(value, bool): row[fieldname] = int(value) else: row[fieldname] = value save_fieldnames = self.fieldnames self.fieldnames = self._fieldnames try: result = super(DictWriter, self).writerow(row) finally: self.fieldnames = save_fieldnames return result