Repository: getmoto/moto

Issue:
Logs filter-log-events ignores filterPattern argument.
When a `filterPattern` is given to `filter_log_events`  the filter is ignored.

e.g.

```
        malformed = {"message": "hello", "timestamp": 100}

        logs_client.put_log_events(
            logGroupName=log_group,
            logStreamName=log_streams[0],
            logEvents=[malformed],
        )

       res = logs_client.filter_log_events(
            logGroupName=log_group,
            filterPattern='{$.my_json_field = "foo"}',
            startTime=0,
            endTime=12345667,
        )
 
      # Fails
       assert len(res["events"]) == 0 
```

On 1.3.9 locally (installed with pip), but the problem exists on master.

Here's the specific LOC where it just ignores `filter_pattern`: https://github.com/spulec/moto/blob/master/moto/logs/models.py#L126

I think it's probably reasonable to support basic key equality for json filters, as well as simple matching on text. Anything beyond that might get tricky, but you can throw an error in that case instead of silently ignoring.

At the very least, raising NotImplemented() when filter_pattern is non-empty would be desirable.


Discussion:
Thanks; I am going to set this as a feature request for us to implement filter_pattern.

Resolving patch:
diff --git a/moto/logs/models.py b/moto/logs/models.py
--- a/moto/logs/models.py
+++ b/moto/logs/models.py
@@ -125,6 +125,9 @@ def get_index_from_paging_token(token):
         return events_page, get_paging_token_from_index(back_index, True), get_paging_token_from_index(next_index)
 
     def filter_log_events(self, log_group_name, log_stream_names, start_time, end_time, limit, next_token, filter_pattern, interleaved):
+        if filter_pattern:
+            raise NotImplementedError('filter_pattern is not yet implemented')
+
         def filter_func(event):
             if start_time and event.timestamp < start_time:
                 return False


Test patch:
diff --git a/tests/test_logs/test_logs.py b/tests/test_logs/test_logs.py
--- a/tests/test_logs/test_logs.py
+++ b/tests/test_logs/test_logs.py
@@ -1,10 +1,12 @@
 import boto3
+import os
 import sure  # noqa
 import six
 from botocore.exceptions import ClientError
 
 from moto import mock_logs, settings
 from nose.tools import assert_raises
+from nose import SkipTest
 
 _logs_region = 'us-east-1' if settings.TEST_SERVER_MODE else 'us-west-2'
 
@@ -128,6 +130,36 @@ def test_filter_logs_interleaved():
         resulting_event['timestamp'].should.equal(original_message['timestamp'])
         resulting_event['message'].should.equal(original_message['message'])
 
+
+@mock_logs
+def test_filter_logs_raises_if_filter_pattern():
+    if os.environ.get('TEST_SERVER_MODE', 'false').lower() == 'true':
+        raise SkipTest('Does not work in server mode due to error in Workzeug')
+    conn = boto3.client('logs', 'us-west-2')
+    log_group_name = 'dummy'
+    log_stream_name = 'stream'
+    conn.create_log_group(logGroupName=log_group_name)
+    conn.create_log_stream(
+        logGroupName=log_group_name,
+        logStreamName=log_stream_name
+    )
+    messages = [
+        {'timestamp': 0, 'message': 'hello'},
+        {'timestamp': 0, 'message': 'world'}
+    ]
+    conn.put_log_events(
+        logGroupName=log_group_name,
+        logStreamName=log_stream_name,
+        logEvents=messages
+    )
+    with assert_raises(NotImplementedError):
+        conn.filter_log_events(
+            logGroupName=log_group_name,
+            logStreamNames=[log_stream_name],
+            filterPattern='{$.message = "hello"}',
+        )
+
+
 @mock_logs
 def test_put_retention_policy():
     conn = boto3.client('logs', 'us-west-2')
@@ -142,6 +174,7 @@ def test_put_retention_policy():
 
     response = conn.delete_log_group(logGroupName=log_group_name)
 
+
 @mock_logs
 def test_delete_retention_policy():
     conn = boto3.client('logs', 'us-west-2')