Repository: google/timesketch

Issue:
tsctl to support TSV files
`tsctl` currently supports reading CSV files, however, often times its easier/less likely data gets broken by using _tab_ delimited files.

This is trivial to implement, e.g - :
1.  add the option `tsv2ts` to [`shell_manager`](https://github.com/hiddenillusion/timesketch/blob/master/tsctl#L424)
2. in `CreateTimelineFromCsv()`have an option for _delimiter_ and if `tsv2ts` was provided, change the CSV [`reader`](https://github.com/hiddenillusion/timesketch/blob/master/tsctl#L412) delimiter to a tab.


Discussion:
Great idea, this should be simple enough. Do you have time to code this up? Let me know otherwise and I'll take a look asap.
ack, will submit a PR

Resolving patch:
diff --git a/timesketch/lib/tasks.py b/timesketch/lib/tasks.py
--- a/timesketch/lib/tasks.py
+++ b/timesketch/lib/tasks.py
@@ -104,7 +104,7 @@ def run_plaso(source_file_path, timeline_name, index_name, source_type,
 
 @celery.task(track_started=True)
 def run_csv_jsonl(source_file_path, timeline_name, index_name, source_type,
-                  username=None):
+                  delimiter=None, username=None):
     """Create a Celery task for processing a CSV or JSONL file.
 
     Args:
@@ -112,6 +112,7 @@ def run_csv_jsonl(source_file_path, timeline_name, index_name, source_type,
         timeline_name: Name of the Timesketch timeline.
         index_name: Name of the datastore index.
         source_type: Type of file, csv or jsonl.
+        delimiter: Character used as a field separator
         username: Username of the user who will own the timeline.
 
     Returns:
@@ -139,7 +140,7 @@ def run_csv_jsonl(source_file_path, timeline_name, index_name, source_type,
     # all possible errors and exit the task.
     try:
         es.create_index(index_name=index_name, doc_type=event_type)
-        for event in read_and_validate(source_file_path):
+        for event in read_and_validate(source_file_path, delimiter):
             es.import_event(index_name, event_type, event)
         # Import the remaining events
         total_events = es.import_event(index_name, event_type)
diff --git a/timesketch/lib/utils.py b/timesketch/lib/utils.py
--- a/timesketch/lib/utils.py
+++ b/timesketch/lib/utils.py
@@ -37,18 +37,19 @@ def random_color():
     return u'{0:02X}{1:02X}{2:02X}'.format(rgb[0], rgb[1], rgb[2])
 
 
-def read_and_validate_csv(path):
-    """Generator for reading a CSV file.
+def read_and_validate_csv(path, delimiter):
+    """Generator for reading a CSV or TSV file.
 
     Args:
-        path: Path to the CSV file
+        path: Path to the file
+        delimiter: character used as a field separator
     """
     # Columns that must be present in the CSV file
     mandatory_fields = [u'message', u'datetime', u'timestamp_desc']
 
     with open(path, 'rb') as fh:
 
-        reader = csv.DictReader(fh)
+        reader = csv.DictReader(fh, delimiter=delimiter.decode('string_escape'))
         csv_header = reader.fieldnames
         missing_fields = []
         # Validate the CSV header
@@ -70,7 +71,7 @@ def read_and_validate_csv(path):
             yield row
 
 
-def read_and_validate_jsonl(path):
+def read_and_validate_jsonl(path, _):
     """Generator for reading a JSONL (json lines) file.
 
     Args:


Test patch: