prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  APM Agent Serialization Error
  **Describe the bug**: APM Agent crashes when using Python AWS SDK's builder for DynamoDB Key condition expressions.
  
  **To Reproduce**
  
  1. Import `from boto3.dynamodb.conditions import Key` and make a DynamoDB query that includes `KeyConditionExpression` option with a value generated by `Key` class. Example Broken Code:
  
  ```
  SESSION = boto3.Session(region_name="us-west-2",)
  DYNAMODB_TABLE = SESSION.resource("dynamodb").Table("TableName")
  
  options = {
      "KeyConditionExpression": Key("primary_key").eq(1)
  }
  
  result = DYNAMODB_TABLE.query(**options)
  ```
  
  2. If APM Agent is running it will crash with the following exception when above code executes:
  ```
  Exception in thread eapm event processor thread:
  Traceback (most recent call last):
    File "/var/lang/lib/python3.8/threading.py", line 932, in _bootstrap_inner
      self.run()
    File "/var/lang/lib/python3.8/threading.py", line 870, in run
      self._target(*self._args, **self._kwargs)
    File "/var/task/elasticapm/transport/base.py", line 145, in _process_queue
      buffer.write((self._json_serializer({event_type: data}) + "\n").encode("utf-8"))
    File "/var/task/elasticapm/utils/json_encoder.py", line 63, in dumps
      return json.dumps(value, cls=BetterJSONEncoder, **kwargs)
    File "/var/lang/lib/python3.8/json/__init__.py", line 234, in dumps
      return cls(
    File "/var/lang/lib/python3.8/json/encoder.py", line 199, in encode
      chunks = self.iterencode(o, _one_shot=True)
    File "/var/lang/lib/python3.8/json/encoder.py", line 257, in iterencode
      return _iterencode(o, 0)
    File "/var/task/elasticapm/utils/json_encoder.py", line 55, in default
      return super(BetterJSONEncoder, self).default(obj)
    File "/var/lang/lib/python3.8/json/encoder.py", line 179, in default
      raise TypeError(f'Object of type {o.__class__.__name__} '
  TypeError: Object of type Equals is not JSON serializable
  ```
  
  3. Excluding the usage of `Key` class for building Condition Expressions avoids the bug. Example Working Code:
  ```
  SESSION = boto3.Session(region_name="us-west-2",)
  DYNAMODB_TABLE = SESSION.resource("dynamodb").Table("TableName")
  
  options = {
      "KeyConditionExpression": "#PrimaryKey = :value",
      "ExpressionAttributeNames": {"#PrimaryKey": "primary_key"},
      "ExpressionAttributeValues": {":value": 1}
  }
  
  result = DYNAMODB_TABLE.query(**options)
  ```
  
  **Environment (please complete the following information)**
  - OS: Linux
  - Python version: 3.8
  - Framework and version [e.g. Django 2.1]: Not Applicable
  - APM Server version: 7.13.4
  - Agent version: 6.3.3
  
  </issue>
  <code>
  [start of elasticapm/utils/json_encoder.py]
  1 #  BSD 3-Clause License
  2 #
  3 #  Copyright (c) 2012, the Sentry Team, see AUTHORS for more details
  4 #  Copyright (c) 2019, Elasticsearch BV
  5 #  All rights reserved.
  6 #
  7 #  Redistribution and use in source and binary forms, with or without
  8 #  modification, are permitted provided that the following conditions are met:
  9 #
  10 #  * Redistributions of source code must retain the above copyright notice, this
  11 #    list of conditions and the following disclaimer.
  12 #
  13 #  * Redistributions in binary form must reproduce the above copyright notice,
  14 #    this list of conditions and the following disclaimer in the documentation
  15 #    and/or other materials provided with the distribution.
  16 #
  17 #  * Neither the name of the copyright holder nor the names of its
  18 #    contributors may be used to endorse or promote products derived from
  19 #    this software without specific prior written permission.
  20 #
  21 #  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  22 #  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23 #  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  24 #  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  25 #  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26 #  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  27 #  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  28 #  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  29 #  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  30 
  31 
  32 import datetime
  33 import decimal
  34 import uuid
  35 
  36 try:
  37     import json
  38 except ImportError:
  39     import simplejson as json
  40 
  41 
  42 class BetterJSONEncoder(json.JSONEncoder):
  43     ENCODERS = {
  44         set: list,
  45         frozenset: list,
  46         datetime.datetime: lambda obj: obj.strftime("%Y-%m-%dT%H:%M:%S.%fZ"),
  47         uuid.UUID: lambda obj: obj.hex,
  48         bytes: lambda obj: obj.decode("utf-8", errors="replace"),
  49         decimal.Decimal: lambda obj: float(obj),
  50     }
  51 
  52     def default(self, obj):
  53         if type(obj) in self.ENCODERS:
  54             return self.ENCODERS[type(obj)](obj)
  55         return super(BetterJSONEncoder, self).default(obj)
  56 
  57 
  58 def better_decoder(data):
  59     return data
  60 
  61 
  62 def dumps(value, **kwargs):
  63     return json.dumps(value, cls=BetterJSONEncoder, **kwargs)
  64 
  65 
  66 def loads(value, **kwargs):
  67     return json.loads(value, object_hook=better_decoder)
  68
  [end of elasticapm/utils/json_encoder.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/elasticapm/utils/json_encoder.py b/elasticapm/utils/json_encoder.py
  --- a/elasticapm/utils/json_encoder.py
  +++ b/elasticapm/utils/json_encoder.py
  @@ -52,7 +52,10 @@
       def default(self, obj):
           if type(obj) in self.ENCODERS:
               return self.ENCODERS[type(obj)](obj)
  -        return super(BetterJSONEncoder, self).default(obj)
  +        try:
  +            return super(BetterJSONEncoder, self).default(obj)
  +        except TypeError:
  +            return str(obj)
   
   
   def better_decoder(data):
  
verification_info: {"golden_diff": "diff --git a/elasticapm/utils/json_encoder.py b/elasticapm/utils/json_encoder.py\n--- a/elasticapm/utils/json_encoder.py\n+++ b/elasticapm/utils/json_encoder.py\n@@ -52,7 +52,10 @@\n     def default(self, obj):\n         if type(obj) in self.ENCODERS:\n             return self.ENCODERS[type(obj)](obj)\n-        return super(BetterJSONEncoder, self).default(obj)\n+        try:\n+            return super(BetterJSONEncoder, self).default(obj)\n+        except TypeError:\n+            return str(obj)\n \n \n def better_decoder(data):\n", "issue": "APM Agent Serialization Error\n**Describe the bug**: APM Agent crashes when using Python AWS SDK's builder for DynamoDB Key condition expressions.\r\n\r\n**To Reproduce**\r\n\r\n1. Import `from boto3.dynamodb.conditions import Key` and make a DynamoDB query that includes `KeyConditionExpression` option with a value generated by `Key` class. Example Broken Code:\r\n\r\n```\r\nSESSION = boto3.Session(region_name=\"us-west-2\",)\r\nDYNAMODB_TABLE = SESSION.resource(\"dynamodb\").Table(\"TableName\")\r\n\r\noptions = {\r\n    \"KeyConditionExpression\": Key(\"primary_key\").eq(1)\r\n}\r\n\r\nresult = DYNAMODB_TABLE.query(**options)\r\n```\r\n\r\n2. If APM Agent is running it will crash with the following exception when above code executes:\r\n```\r\nException in thread eapm event processor thread:\r\nTraceback (most recent call last):\r\n  File \"/var/lang/lib/python3.8/threading.py\", line 932, in _bootstrap_inner\r\n    self.run()\r\n  File \"/var/lang/lib/python3.8/threading.py\", line 870, in run\r\n    self._target(*self._args, **self._kwargs)\r\n  File \"/var/task/elasticapm/transport/base.py\", line 145, in _process_queue\r\n    buffer.write((self._json_serializer({event_type: data}) + \"\\n\").encode(\"utf-8\"))\r\n  File \"/var/task/elasticapm/utils/json_encoder.py\", line 63, in dumps\r\n    return json.dumps(value, cls=BetterJSONEncoder, **kwargs)\r\n  File \"/var/lang/lib/python3.8/json/__init__.py\", line 234, in dumps\r\n    return cls(\r\n  File \"/var/lang/lib/python3.8/json/encoder.py\", line 199, in encode\r\n    chunks = self.iterencode(o, _one_shot=True)\r\n  File \"/var/lang/lib/python3.8/json/encoder.py\", line 257, in iterencode\r\n    return _iterencode(o, 0)\r\n  File \"/var/task/elasticapm/utils/json_encoder.py\", line 55, in default\r\n    return super(BetterJSONEncoder, self).default(obj)\r\n  File \"/var/lang/lib/python3.8/json/encoder.py\", line 179, in default\r\n    raise TypeError(f'Object of type {o.__class__.__name__} '\r\nTypeError: Object of type Equals is not JSON serializable\r\n```\r\n\r\n3. Excluding the usage of `Key` class for building Condition Expressions avoids the bug. Example Working Code:\r\n```\r\nSESSION = boto3.Session(region_name=\"us-west-2\",)\r\nDYNAMODB_TABLE = SESSION.resource(\"dynamodb\").Table(\"TableName\")\r\n\r\noptions = {\r\n    \"KeyConditionExpression\": \"#PrimaryKey = :value\",\r\n    \"ExpressionAttributeNames\": {\"#PrimaryKey\": \"primary_key\"},\r\n    \"ExpressionAttributeValues\": {\":value\": 1}\r\n}\r\n\r\nresult = DYNAMODB_TABLE.query(**options)\r\n```\r\n\r\n**Environment (please complete the following information)**\r\n- OS: Linux\r\n- Python version: 3.8\r\n- Framework and version [e.g. Django 2.1]: Not Applicable\r\n- APM Server version: 7.13.4\r\n- Agent version: 6.3.3\n", "before_files": [{"content": "#  BSD 3-Clause License\n#\n#  Copyright (c) 2012, the Sentry Team, see AUTHORS for more details\n#  Copyright (c) 2019, Elasticsearch BV\n#  All rights reserved.\n#\n#  Redistribution and use in source and binary forms, with or without\n#  modification, are permitted provided that the following conditions are met:\n#\n#  * Redistributions of source code must retain the above copyright notice, this\n#    list of conditions and the following disclaimer.\n#\n#  * Redistributions in binary form must reproduce the above copyright notice,\n#    this list of conditions and the following disclaimer in the documentation\n#    and/or other materials provided with the distribution.\n#\n#  * Neither the name of the copyright holder nor the names of its\n#    contributors may be used to endorse or promote products derived from\n#    this software without specific prior written permission.\n#\n#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n#  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\n#  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n#  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n#  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n#  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n#  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n\n\nimport datetime\nimport decimal\nimport uuid\n\ntry:\n    import json\nexcept ImportError:\n    import simplejson as json\n\n\nclass BetterJSONEncoder(json.JSONEncoder):\n    ENCODERS = {\n        set: list,\n        frozenset: list,\n        datetime.datetime: lambda obj: obj.strftime(\"%Y-%m-%dT%H:%M:%S.%fZ\"),\n        uuid.UUID: lambda obj: obj.hex,\n        bytes: lambda obj: obj.decode(\"utf-8\", errors=\"replace\"),\n        decimal.Decimal: lambda obj: float(obj),\n    }\n\n    def default(self, obj):\n        if type(obj) in self.ENCODERS:\n            return self.ENCODERS[type(obj)](obj)\n        return super(BetterJSONEncoder, self).default(obj)\n\n\ndef better_decoder(data):\n    return data\n\n\ndef dumps(value, **kwargs):\n    return json.dumps(value, cls=BetterJSONEncoder, **kwargs)\n\n\ndef loads(value, **kwargs):\n    return json.loads(value, object_hook=better_decoder)\n", "path": "elasticapm/utils/json_encoder.py"}]}