feat(grouping): Additional message parameterizations
diff --git a/src/sentry/grouping/strategies/message.py b/src/sentry/grouping/strategies/message.py
index 5692027d75c347..d3a17b939181db 100644
--- a/src/sentry/grouping/strategies/message.py
+++ b/src/sentry/grouping/strategies/message.py
@@ -15,7 +15,7 @@
 from sentry.utils import metrics
 
 _parameterization_regex = re.compile(
-    # The `(?x)` tells the regex compiler to ingore comments and unescaped whitespace,
+    # The `(?x)` tells the regex compiler to ignore comments and unescaped whitespace,
     # so we can use newlines and indentation for better legibility.
     r"""(?x)
     (?P<email>
@@ -64,6 +64,32 @@
         \b[0-9a-fA-F]{32}\b
     ) |
     (?P<date>
+        # No word boundaries required around dates. Should there be?
+        # RFC822, RFC1123, RFC1123Z
+        ((?:Sun|Mon|Tue|Wed|Thu|Fri|Sat),\s\d{1,2}\s(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s\d{2,4}\s\d{1,2}:\d{1,2}(:\d{1,2})?\s([-\+][\d]{2}[0-5][\d]|(?:UT|GMT|(?:E|C|M|P)(?:ST|DT)|[A-IK-Z])))
+        |
+        # RFC850
+        ((?:Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday),\s\d{2}-(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-\d{2}\s\d{2}:\d{2}:\d{2}\s(?:UT|GMT|(?:E|C|M|P)(?:ST|DT)|[A-IK-Z]))
+        |
+        # RFC3339, RFC3339Nano
+        (\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?Z?([+-]?\d{2}:\d{2})?)
+        |
+        # LongDate
+        ((?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s+[0-3]\d,\s+\d{4})
+        |
+        # Datetime
+        (\d{4}-[01]\d-[0-3]\d\s[0-2]\d:[0-5]\d:[0-5]\d)
+        |
+        # Kitchen
+        (\d{1,2}:\d{2}(:\d{2})?(?: [aApP][Mm])?)
+        |
+        # Date
+        (\d{4}-[01]\d-[0-3]\d)
+        |
+        # Time
+        ([0-2]\d:[0-5]\d:[0-5]\d)
+        |
+        # Old Date Formats, TODO: possibly safe to remove?
         (
             (\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z))|
             (\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))|
@@ -87,6 +113,9 @@
         ) |
         (datetime.datetime\(.*?\))
     ) |
+    (?P<duration>
+        \b\d+ms\b
+    ) |
     (?P<hex>
         \b0[xX][0-9a-fA-F]+\b
     ) |
@@ -142,7 +171,12 @@ def _handle_match(match: Match[str]) -> str:
                 # For `quoted_str` and `bool` we want to preserve the `=` symbol, which we include in
                 # the match in order not to replace random quoted strings and the words 'true' and 'false'
                 # in contexts other than key-value pairs
-                return f"=<{key}>" if key in ["quoted_str", "bool"] else f"<{key}>"
+                if key in ["quoted_str", "bool"]:
+                    return f"=<{key}>"
+                elif key == "json_str_val":
+                    return f": <{key}>"
+                else:
+                    return f"<{key}>"
         return ""
 
     return _parameterization_regex.sub(_handle_match, trimmed)
diff --git a/tests/sentry/grouping/test_normalize_message.py b/tests/sentry/grouping/test_normalize_message.py
new file mode 100644
index 00000000000000..567ad1c9f91aa3
--- /dev/null
+++ b/tests/sentry/grouping/test_normalize_message.py
@@ -0,0 +1,94 @@
+import pytest
+
+from sentry.grouping.strategies.message import normalize_message_for_grouping
+
+
+@pytest.mark.parametrize(
+    ("name", "input", "expected"),
+    [
+        ("email", """blah test@email.com had a problem""", """blah <email> had a problem"""),
+        ("url", """blah http://some.email.com had a problem""", """blah <url> had a problem"""),
+        (
+            "url - existing behavior",
+            """blah tcp://user:pass@email.com:10 had a problem""",
+            """blah tcp://user:<email>:<int> had a problem""",
+        ),
+        ("ip", """blah 0.0.0.0 had a problem""", """blah <ip> had a problem"""),
+        (
+            "UUID",
+            """blah 7c1811ed-e98f-4c9c-a9f9-58c757ff494f had a problem""",
+            """blah <uuid> had a problem""",
+        ),
+        (
+            "SHA1",
+            """blah 5fc35719b9cf96ec602dbc748ff31c587a46961d had a problem""",
+            """blah <sha1> had a problem""",
+        ),
+        (
+            "MD5",
+            """blah 0751007cd28df267e8e051b51f918c60 had a problem""",
+            """blah <md5> had a problem""",
+        ),
+        (
+            "Date",
+            """blah 2024-02-20T22:16:36 had a problem""",
+            """blah <date> had a problem""",
+        ),
+        (
+            "Date RFC822",
+            """blah Mon, 02 Jan 06 15:04 MST had a problem""",
+            """blah <date> had a problem""",
+        ),
+        (
+            "Date RFC822Z",
+            """blah Mon, 02 Jan 06 15:04 -0700 had a problem""",
+            """blah <date> had a problem""",
+        ),
+        (
+            "Date RFC850",
+            """blah Monday, 02-Jan-06 15:04:05 MST had a problem""",
+            """blah <date> had a problem""",
+        ),
+        (
+            "Date RFC1123",
+            """blah Mon, 02 Jan 2006 15:04:05 MST had a problem""",
+            """blah <date> had a problem""",
+        ),
+        (
+            "Date RFC1123Z",
+            """blah Mon, 02 Jan 2006 15:04:05 -0700 had a problem""",
+            """blah <date> had a problem""",
+        ),
+        (
+            "Date RFC3339",
+            """blah 2006-01-02T15:04:05Z07:00 had a problem""",
+            """blah <date> had a problem""",
+        ),
+        (
+            "Date RFC3339Nano",
+            """blah 2006-01-02T15:04:05.999999999Z07:00 had a problem""",
+            """blah <date> had a problem""",
+        ),
+        ("Date plain", """blah 2006-01-02 had a problem""", """blah <date> had a problem"""),
+        ("Date - long", """blah Jan 18, 2019 had a problem""", """blah <date> had a problem"""),
+        (
+            "Date - Datetime",
+            """blah 2006-01-02 15:04:05 had a problem""",
+            """blah <date> had a problem""",
+        ),
+        ("Date - Kitchen", """blah 3:04PM had a problem""", """blah <date> had a problem"""),
+        ("Date - Time", """blah 15:04:05 had a problem""", """blah <date> had a problem"""),
+        ("hex", """blah 0x9af8c3b had a problem""", """blah <hex> had a problem"""),
+        ("float", """blah 0.23 had a problem""", """blah <float> had a problem"""),
+        ("int", """blah 23 had a problem""", """blah <int> had a problem"""),
+        ("quoted str", """blah b="1" had a problem""", """blah b=<quoted_str> had a problem"""),
+        ("bool", """blah a=true had a problem""", """blah a=<bool> had a problem"""),
+        (
+            "Duration - ms",
+            """blah connection failed after 12345ms""",
+            """blah connection failed after <duration>""",
+        ),
+    ],
+)
+def test_normalize_message(name, input, expected):
+    assert expected == normalize_message_for_grouping(input), f"Case {name} Failed"

Add additional parameterization regular expressions. 

This proposes small discrete improvements to parameterization. This PR is the uncontroversial ones. Controversial ones now live in: https://github.com/getsentry/sentry/pull/65679

* Support more date formats. Notably RFC822, RFC1123, RFC1123Z, RFC850, RFC3339, RFC3339Nano, and your run of the mill “Kitchen” 3:49pm were missing

It also adds non-exhaustive tests for `test_normalize_message`