class_docstr: Encapsulates a single alert and handles serializing to Dynamo and merging.
class_docstr_tok: ["Encapsulates","a","single","alert","and","handles","serializing","to","Dynamo","and","merging","."]
docstr: Combine a list of alerts into a new merged alert.
  
  The caller is responsible for determining *which* alerts should be merged, this just
  implements the merge algorithm.
  
  Args:
      alerts (list): List of alerts to merge.
          These should all have the same values for their merge keys.
  
  Returns:
      Alert: A new alert whose record is formed by merging the records of all the alerts.
          The merged alert outputs are a union of all outputs in the original alerts.
          Other information (rule name, description, etc) is copied from the first alert.
docstr_tok: ["Combine","a","list","of","alerts","into","a","new","merged","alert",".","The","caller","is","responsible","for","determining","*","which","*","alerts","should","be","merged",",","this","just","implements","the","merge","algorithm",".","Args",":","alerts","(","list",")",":","List","of","alerts","to","merge",".","These","should","all","have","the","same","values","for","their","merge","keys",".","Returns",":","Alert",":","A","new","alert","whose","record","is","formed","by","merging","the","records","of","all","the","alerts",".","The","merged","alert","outputs","are","a","union","of","all","outputs","in","the","original","alerts",".","Other","information","(","rule","name",",","description",",","etc",")","is","copied","from","the","first","alert","."]
code: def merge(cls, alerts):
      """Combine a list of alerts into a new merged alert.
  
      The caller is responsible for determining *which* alerts should be merged, this just
      implements the merge algorithm.
  
      Args:
          alerts (list): List of alerts to merge.
              These should all have the same values for their merge keys.
  
      Returns:
          Alert: A new alert whose record is formed by merging the records of all the alerts.
              The merged alert outputs are a union of all outputs in the original alerts.
              Other information (rule name, description, etc) is copied from the first alert.
      """
      alerts = sorted(alerts)  # Put alerts in chronological order.
      merge_keys = set(alerts[0].merge_by_keys)
      # Remove merge keys from the alert record, so that it doesn't show up in common/diff
      records = [
          cls._clean_record(alert.record, merge_keys)
          for alert in alerts
      ]
      common = cls._compute_common(records)
  
      # Keys are named such that more important information is at the beginning alphabetically.
      new_record = {
          "AlertCount": len(alerts),
          "AlertTimeFirst": min(
              alert.created for alert in alerts
          ).strftime(cls.DATETIME_FORMAT),
          "AlertTimeLast": max(
              alert.created for alert in alerts
          ).strftime(cls.DATETIME_FORMAT),
          "MergedBy": {
              key: utils.get_first_key(alerts[0].record, key, "(n/a)")
              for key in merge_keys
          },
          "OtherCommonKeys": common,
          "ValueDiffs": {
              alert.created.strftime(
                  cls.DATETIME_FORMAT
              ): cls._compute_diff(common, record)
              for alert, record in zip(alerts, records)
          },
      }
  
      # TODO: the cluster, log_source, source_entity, etc, could be different between alerts
      return cls(
          alerts[0].rule_name,
          new_record,
          alerts[-1].outputs,  # Use the most recent set of outputs
          cluster=alerts[0].cluster,
          context=alerts[0].context,
          log_source=alerts[0].log_source,
          log_type=alerts[0].log_type,
          publishers=alerts[0].publishers,
          rule_description=alerts[0].rule_description,
          source_entity=alerts[0].source_entity,
          source_service=alerts[0].source_service,
          staged=any(alert.staged for alert in alerts),
      )
  
imports: from datetime import datetime, timedelta
  import json
  import uuid
  from streamalert.shared import resources, utils
label_desc: Use image node_id 15 for calling the Alert obj's underlying member method code with example usage: obj.merge(cls, alerts) and returns: cls