From af4fa9413b91759fede56d5e83056109ea4aca02 Mon Sep 17 00:00:00 2001
From: Masha Lifshin <mlifshin@mozilla.com>
Date: Fri, 21 Nov 2025 18:43:29 -0800
Subject: [PATCH 1/7] Add support for string_list metric in go server

---
 glean_parser/go_server.py               | 4 +++-
 glean_parser/templates/go_server.jinja2 | 3 +++
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/glean_parser/go_server.py b/glean_parser/go_server.py
index 9f8fdfd9d..2eb4cbac2 100644
--- a/glean_parser/go_server.py
+++ b/glean_parser/go_server.py
@@ -32,7 +32,7 @@
 
 # Adding a metric here will require updating the `generate_metric_type` function
 # and require adjustments to `metrics` variables the the template.
-SUPPORTED_METRIC_TYPES = ["string", "quantity", "event", "datetime", "boolean"]
+SUPPORTED_METRIC_TYPES = ["string", "quantity", "event", "datetime", "boolean", "string_list"]
 
 
 def generate_ping_type_name(ping_name: str) -> str:
@@ -68,6 +68,8 @@ def generate_metric_type(metric_type: str) -> str:
         return "bool"
     elif metric_type == "datetime":
         return "time.Time"
+    elif metric_type == "string_list":
+        return "[]string"
     else:
         print("❌ Unable to generate Go type from metric type: " + metric_type)
         exit
diff --git a/glean_parser/templates/go_server.jinja2 b/glean_parser/templates/go_server.jinja2
index f3ebb1481..c77e54736 100644
--- a/glean_parser/templates/go_server.jinja2
+++ b/glean_parser/templates/go_server.jinja2
@@ -14,6 +14,7 @@ import (
     "fmt"
     "io"
     "strconv"
+    "strings"
     "time"
 
     "github.com/google/uuid"
@@ -261,6 +262,8 @@ func (g GleanEventsLogger) Record{{ ping|ping_type_name }}(
         {% for metric in metrics %}
             {% if metric_type == 'datetime' %}
             "{{ metric|metric_name }}": params.{{ metric|metric_argument_name }}.Format("2006-01-02T15:04:05.000Z"),
+            {% elif metric_type == 'string_list' %}
+            "{{ metric|metric_name }}": strings.Join(params.{{ metric|metric_argument_name }}, ","),
             {% else %}
             "{{ metric|metric_name }}": params.{{ metric|metric_argument_name }},
             {% endif %}

From c1df5c6230b162b1e571ef3e103a690da2578808 Mon Sep 17 00:00:00 2001
From: Masha Lifshin <mlifshin@mozilla.com>
Date: Thu, 4 Dec 2025 18:34:16 -0800
Subject: [PATCH 2/7] Update tests for go server string_list metric support

---
 .../data/go_server_custom_ping_only_metrics.yaml | 15 +++++++++++++++
 ...go_server_events_and_custom_ping_metrics.yaml | 16 ++++++++++++++++
 tests/data/go_server_events_only_metrics.yaml    | 15 +++++++++++++++
 tests/data/go_server_metrics_unsupported.yaml    | 15 ---------------
 tests/data/server_custom_ping_only_compare.go    |  5 +++++
 .../server_events_and_custom_ping_compare.go     |  9 +++++++++
 tests/data/server_events_only_compare.go         |  5 +++++
 tests/test_go_server.py                          |  3 +--
 8 files changed, 66 insertions(+), 17 deletions(-)

diff --git a/tests/data/go_server_custom_ping_only_metrics.yaml b/tests/data/go_server_custom_ping_only_metrics.yaml
index 201b130fe..54063171e 100644
--- a/tests/data/go_server_custom_ping_only_metrics.yaml
+++ b/tests/data/go_server_custom_ping_only_metrics.yaml
@@ -66,6 +66,21 @@ metric:
       - TBD
     expires: never
 
+  request_string_list:
+    type: string_list
+    description: >
+      Test string_list metric
+    lifetime: application
+    send_in_pings:
+      - server-telemetry-scenario-one
+    notification_emails:
+      - CHANGE-ME@example.com
+    bugs:
+      - TBD
+    data_reviews:
+      - TBD
+    expires: never
+
 backend:
   special_event:
     type: event
diff --git a/tests/data/go_server_events_and_custom_ping_metrics.yaml b/tests/data/go_server_events_and_custom_ping_metrics.yaml
index b1cae47b2..f289034bb 100644
--- a/tests/data/go_server_events_and_custom_ping_metrics.yaml
+++ b/tests/data/go_server_events_and_custom_ping_metrics.yaml
@@ -70,6 +70,22 @@ metric:
       - TBD
     expires: never
 
+  request_string_list:
+    type: string_list
+    description: >
+      Test string_list metric
+    lifetime: application
+    send_in_pings:
+      - events
+      - server-telemetry-scenario-one
+    notification_emails:
+      - CHANGE-ME@example.com
+    bugs:
+      - TBD
+    data_reviews:
+      - TBD
+    expires: never
+
 backend:
   test_event:
     type: event
diff --git a/tests/data/go_server_events_only_metrics.yaml b/tests/data/go_server_events_only_metrics.yaml
index 624f815fc..70ea0d05e 100644
--- a/tests/data/go_server_events_only_metrics.yaml
+++ b/tests/data/go_server_events_only_metrics.yaml
@@ -66,6 +66,21 @@ metric:
       - TBD
     expires: never
 
+  request_string_list:
+    type: string_list
+    description: >
+      Test string_list metric
+    lifetime: application
+    send_in_pings:
+      - events
+    notification_emails:
+      - CHANGE-ME@example.com
+    bugs:
+      - TBD
+    data_reviews:
+      - TBD
+    expires: never
+
 backend:
   test_event:
     type: event
diff --git a/tests/data/go_server_metrics_unsupported.yaml b/tests/data/go_server_metrics_unsupported.yaml
index 811c4cdf4..e0e475e37 100644
--- a/tests/data/go_server_metrics_unsupported.yaml
+++ b/tests/data/go_server_metrics_unsupported.yaml
@@ -60,21 +60,6 @@ metric:
           attribute_two:
             type: number
 
-  string_list:
-    type: string_list
-    description: >
-      string list
-    bugs:
-      - TBD
-    data_reviews:
-      - TBD
-    notification_emails:
-      - CHANGE-ME@example.com
-    lifetime: application
-    expires: never
-    send_in_pings:
-      - events
-
   timespan:
     type: timespan
     description: >
diff --git a/tests/data/server_custom_ping_only_compare.go b/tests/data/server_custom_ping_only_compare.go
index 36670f5b1..6d5d5f9cd 100644
--- a/tests/data/server_custom_ping_only_compare.go
+++ b/tests/data/server_custom_ping_only_compare.go
@@ -13,6 +13,7 @@ import (
     "fmt"
     "io"
     "strconv"
+    "strings"
     "time"
 
     "github.com/google/uuid"
@@ -218,6 +219,7 @@ type ServerTelemetryScenarioOnePing struct {
     MetricRequestBool bool // boolean
     MetricRequestCount int64 // Test quantity metric
     MetricRequestDatetime time.Time // Test datetime metric
+    MetricRequestStringList []string // Test string_list metric
     Event ServerTelemetryScenarioOnePingEvent // valid event for this ping
 }
 
@@ -239,6 +241,9 @@ func (g GleanEventsLogger) RecordServerTelemetryScenarioOnePing(
         "datetime": {
             "metric.request_datetime": params.MetricRequestDatetime.Format("2006-01-02T15:04:05.000Z"),
         },
+        "string_list": {
+            "metric.request_string_list": strings.Join(params.MetricRequestStringList, ","),
+        },
     }
 
     events := []gleanEvent{}
diff --git a/tests/data/server_events_and_custom_ping_compare.go b/tests/data/server_events_and_custom_ping_compare.go
index 663270858..bf1259ff6 100644
--- a/tests/data/server_events_and_custom_ping_compare.go
+++ b/tests/data/server_events_and_custom_ping_compare.go
@@ -13,6 +13,7 @@ import (
     "fmt"
     "io"
     "strconv"
+    "strings"
     "time"
 
     "github.com/google/uuid"
@@ -218,6 +219,7 @@ type EventsPing struct {
     MetricRequestBool bool // boolean
     MetricRequestCount int64 // Test quantity metric
     MetricRequestDatetime time.Time // Test datetime metric
+    MetricRequestStringList []string // Test string_list metric
     Event EventsPingEvent // valid event for this ping
 }
 
@@ -239,6 +241,9 @@ func (g GleanEventsLogger) RecordEventsPing(
         "datetime": {
             "metric.request_datetime": params.MetricRequestDatetime.Format("2006-01-02T15:04:05.000Z"),
         },
+        "string_list": {
+            "metric.request_string_list": strings.Join(params.MetricRequestStringList, ","),
+        },
     }
 
     events := []gleanEvent{}
@@ -260,6 +265,7 @@ type ServerTelemetryScenarioOnePing struct {
     MetricRequestBool bool // boolean
     MetricRequestCount int64 // Test quantity metric
     MetricRequestDatetime time.Time // Test datetime metric
+    MetricRequestStringList []string // Test string_list metric
 }
 
 // Record and submit `server-telemetry-scenario-one` ping
@@ -280,6 +286,9 @@ func (g GleanEventsLogger) RecordServerTelemetryScenarioOnePing(
         "datetime": {
             "metric.request_datetime": params.MetricRequestDatetime.Format("2006-01-02T15:04:05.000Z"),
         },
+        "string_list": {
+            "metric.request_string_list": strings.Join(params.MetricRequestStringList, ","),
+        },
     }
 
     events := []gleanEvent{}
diff --git a/tests/data/server_events_only_compare.go b/tests/data/server_events_only_compare.go
index 650e6fb74..1c4071054 100644
--- a/tests/data/server_events_only_compare.go
+++ b/tests/data/server_events_only_compare.go
@@ -13,6 +13,7 @@ import (
     "fmt"
     "io"
     "strconv"
+    "strings"
     "time"
 
     "github.com/google/uuid"
@@ -218,6 +219,7 @@ type EventsPing struct {
     MetricRequestBool bool // boolean
     MetricRequestCount int64 // Test quantity metric
     MetricRequestDatetime time.Time // Test datetime metric
+    MetricRequestStringList []string // Test string_list metric
     Event EventsPingEvent // valid event for this ping
 }
 
@@ -239,6 +241,9 @@ func (g GleanEventsLogger) RecordEventsPing(
         "datetime": {
             "metric.request_datetime": params.MetricRequestDatetime.Format("2006-01-02T15:04:05.000Z"),
         },
+        "string_list": {
+            "metric.request_string_list": strings.Join(params.MetricRequestStringList, ","),
+        },
     }
 
     events := []gleanEvent{}
diff --git a/tests/test_go_server.py b/tests/test_go_server.py
index 26b1e2825..f9e206341 100644
--- a/tests/test_go_server.py
+++ b/tests/test_go_server.py
@@ -42,7 +42,6 @@ def test_parser_go_server_metrics_unsupported_type(tmp_path, capsys):
         "boolean",
         "labeled_boolean",
         "labeled_string",
-        "string_list",
         "timespan",
         "uuid",
         "url",
@@ -102,7 +101,7 @@ def test_parser_go_server_events_and_custom_ping(tmp_path):
     assert content == compare
 
 
-def test_parser_go_server_custon_ping_only(tmp_path):
+def test_parser_go_server_custom_ping_only(tmp_path):
     """Test that parser works for definitions that only use custom pings"""
     translate.translate(
         [

From 14cddce5e3bb7fb29564f34a0b4bbbf84dd8d9cb Mon Sep 17 00:00:00 2001
From: Masha Lifshin <mlifshin@mozilla.com>
Date: Fri, 5 Dec 2025 16:28:42 -0800
Subject: [PATCH 3/7] Update CHANGELOG.md

---
 CHANGELOG.md | 1 +
 1 file changed, 1 insertion(+)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 50eeae2c1..005f734b1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,7 @@
 ## Unreleased
 
 - New lint: Warn against event metrics on the `metrics` or `baseline` ping ([#823](https://github.com/mozilla/glean_parser/pull/823))
+- Go server: Add 'string_list' to supported metric types ([#825](https://github.com/mozilla/glean_parser/pull/825))
 
 ## 18.1.1
 

From 506ab87ef4f20436e88cae0276f153dceaab70b7 Mon Sep 17 00:00:00 2001
From: Masha Lifshin <mlifshin@mozilla.com>
Date: Fri, 5 Dec 2025 17:43:14 -0800
Subject: [PATCH 4/7] Update go server validation tests for new test ping yamls

---
 glean_parser/templates/go_server.jinja2 |  2 +-
 tests/test_go_server.py                 | 36 ++++++++++++++-----------
 2 files changed, 21 insertions(+), 17 deletions(-)

diff --git a/glean_parser/templates/go_server.jinja2 b/glean_parser/templates/go_server.jinja2
index c77e54736..a69400276 100644
--- a/glean_parser/templates/go_server.jinja2
+++ b/glean_parser/templates/go_server.jinja2
@@ -263,7 +263,7 @@ func (g GleanEventsLogger) Record{{ ping|ping_type_name }}(
             {% if metric_type == 'datetime' %}
             "{{ metric|metric_name }}": params.{{ metric|metric_argument_name }}.Format("2006-01-02T15:04:05.000Z"),
             {% elif metric_type == 'string_list' %}
-            "{{ metric|metric_name }}": strings.Join(params.{{ metric|metric_argument_name }}, ","),
+            "{{ metric|metric_name }}": fmt.Sprintf("[%s]", strings.Join(params.{{ metric|metric_argument_name }}, "','")),
             {% else %}
             "{{ metric|metric_name }}": params.{{ metric|metric_argument_name }},
             {% endif %}
diff --git a/tests/test_go_server.py b/tests/test_go_server.py
index f9e206341..8790ff4ea 100644
--- a/tests/test_go_server.py
+++ b/tests/test_go_server.py
@@ -169,10 +169,11 @@ def test_run_logging_events_ping(tmp_path):
             IpAddress: "127.0.0.1",
         },
         glean.EventsPing{
-            MetricName:            "string value",
-            MetricRequestBool:     true,
-            MetricRequestCount:    10,
-            MetricRequestDatetime: time.Now(),
+            MetricName:              "string value",
+            MetricRequestBool:       true,
+            MetricRequestCount:      10,
+            MetricRequestDatetime:   time.Now(),
+            MetricRequestStringList: []string{"list", "of", "strings"},
             Event: glean.BackendTestEventEvent{
                 EventFieldString:      "event extra string value",
                 EventFieldQuantity:    100,
@@ -226,10 +227,11 @@ def test_run_logging_custom_ping_without_event(tmp_path):
             IpAddress: "127.0.0.1",
         },
         glean.ServerTelemetryScenarioOnePing{
-            MetricName:            "string value",
-            MetricRequestBool:     true,
-            MetricRequestCount:    20,
-            MetricRequestDatetime: time.Now(),
+            MetricName:             "string value",
+            MetricRequestBool:       true,
+            MetricRequestCount:      20,
+            MetricRequestDatetime:   time.Now(),
+            MetricRequestStringList: []string{"list", "of", "strings"},
         },
     )
     """
@@ -284,10 +286,11 @@ def test_run_logging_discard_writer(tmp_path):
             IpAddress: "127.0.0.1",
         },
         glean.ServerTelemetryScenarioOnePing{
-            MetricName:            "string value",
-            MetricRequestBool:     true,
-            MetricRequestCount:    20,
-            MetricRequestDatetime: time.Now(),
+            MetricName:             "string value",
+            MetricRequestBool:       true,
+            MetricRequestCount:      20,
+            MetricRequestDatetime:   time.Now(),
+            MetricRequestStringList: []string{"list", "of", "strings"},
         },
     )
     if err != nil {
@@ -361,10 +364,11 @@ def test_run_logging_custom_ping_with_event(tmp_path):
             IpAddress: "127.0.0.1",
         },
         glean.ServerTelemetryScenarioOnePing{
-            MetricName:            "string value",
-            MetricRequestBool:     true,
-            MetricRequestCount:    20,
-            MetricRequestDatetime: time.Now(),
+            MetricName:              "string value",
+            MetricRequestBool:       true,
+            MetricRequestCount:      20,
+            MetricRequestDatetime:   time.Now(),
+            MetricRequestStringList: []string{"list", "of", "strings"},
             Event: glean.BackendSpecialEventEvent{
                 EventFieldString: "exta value string",
                 EventFieldQuantity: 30,

From c5c099c0d5a5f5536eaf3c490de0a119813d54a8 Mon Sep 17 00:00:00 2001
From: Masha Lifshin <mlifshin@mozilla.com>
Date: Tue, 9 Dec 2025 08:19:11 -0800
Subject: [PATCH 5/7] Refactor to use json marshaling helper function instead
 of strings lib

---
 glean_parser/templates/go_server.jinja2       | 19 +++++++++++++--
 tests/data/server_custom_ping_only_compare.go | 16 +++++++++++--
 .../server_events_and_custom_ping_compare.go  | 23 ++++++++++++++++---
 tests/data/server_events_only_compare.go      | 16 +++++++++++--
 4 files changed, 65 insertions(+), 9 deletions(-)

diff --git a/glean_parser/templates/go_server.jinja2 b/glean_parser/templates/go_server.jinja2
index a69400276..93616a2fa 100644
--- a/glean_parser/templates/go_server.jinja2
+++ b/glean_parser/templates/go_server.jinja2
@@ -14,7 +14,6 @@ import (
     "fmt"
     "io"
     "strconv"
-    "strings"
     "time"
 
     "github.com/google/uuid"
@@ -221,6 +220,15 @@ func (e {{ event|event_type_name }}) gleanEvent() gleanEvent {
 }
 {% endfor %}
 {% endif %}
+
+{# helper function for stringifying string_list type metrics #}
+func StringListStringify(stringListMetricValue []string) (string, error) {
+    stringListString, err := json.Marshal(stringListMetricValue)
+	if err != nil {
+		return "", err
+	}
+	return string(stringListString), nil
+}
 {# struct & methods for submitting pings #}
 {% for ping, metrics_by_type in pings.items() %}
 {% if metrics_by_type['event'] %}
@@ -255,6 +263,13 @@ func (g GleanEventsLogger) Record{{ ping|ping_type_name }}(
     requestInfo RequestInfo,
     params {{ ping|ping_type_name }},
 ) error {
+    {% for metric in metrics_by_type['string_list'] %}
+    {{ metric|metric_argument_name }}String, error := StringListStringify(params.{{ metric|metric_argument_name }})
+    if error != nil {
+        return error
+    }
+    {% endfor %}
+
     metrics := metrics{
     {% for metric_type, metrics in metrics_by_type.items() %}
     {% if metric_type != 'event' %}
@@ -263,7 +278,7 @@ func (g GleanEventsLogger) Record{{ ping|ping_type_name }}(
             {% if metric_type == 'datetime' %}
             "{{ metric|metric_name }}": params.{{ metric|metric_argument_name }}.Format("2006-01-02T15:04:05.000Z"),
             {% elif metric_type == 'string_list' %}
-            "{{ metric|metric_name }}": fmt.Sprintf("[%s]", strings.Join(params.{{ metric|metric_argument_name }}, "','")),
+            "{{ metric|metric_name }}": {{ metric|metric_argument_name }}String,
             {% else %}
             "{{ metric|metric_name }}": params.{{ metric|metric_argument_name }},
             {% endif %}
diff --git a/tests/data/server_custom_ping_only_compare.go b/tests/data/server_custom_ping_only_compare.go
index 6d5d5f9cd..75f48ab52 100644
--- a/tests/data/server_custom_ping_only_compare.go
+++ b/tests/data/server_custom_ping_only_compare.go
@@ -13,7 +13,6 @@ import (
     "fmt"
     "io"
     "strconv"
-    "strings"
     "time"
 
     "github.com/google/uuid"
@@ -207,6 +206,14 @@ func (e BackendSpecialEventEvent) gleanEvent() gleanEvent {
     )
 }
 
+func StringListStringify(stringListMetricValue []string) (string, error) {
+    stringListString, err := json.Marshal(stringListMetricValue)
+	if err != nil {
+		return "", err
+	}
+	return string(stringListString), nil
+}
+
 type ServerTelemetryScenarioOnePingEvent interface {
     isServerTelemetryScenarioOnePingEvent()
     gleanEvent() gleanEvent
@@ -228,6 +235,11 @@ func (g GleanEventsLogger) RecordServerTelemetryScenarioOnePing(
     requestInfo RequestInfo,
     params ServerTelemetryScenarioOnePing,
 ) error {
+    MetricRequestStringListString, error := StringListStringify(params.MetricRequestStringList)
+    if error != nil {
+        return error
+    }
+
     metrics := metrics{
         "string": {
             "metric.name": params.MetricName,
@@ -242,7 +254,7 @@ func (g GleanEventsLogger) RecordServerTelemetryScenarioOnePing(
             "metric.request_datetime": params.MetricRequestDatetime.Format("2006-01-02T15:04:05.000Z"),
         },
         "string_list": {
-            "metric.request_string_list": strings.Join(params.MetricRequestStringList, ","),
+            "metric.request_string_list": MetricRequestStringListString,
         },
     }
 
diff --git a/tests/data/server_events_and_custom_ping_compare.go b/tests/data/server_events_and_custom_ping_compare.go
index bf1259ff6..627426df6 100644
--- a/tests/data/server_events_and_custom_ping_compare.go
+++ b/tests/data/server_events_and_custom_ping_compare.go
@@ -13,7 +13,6 @@ import (
     "fmt"
     "io"
     "strconv"
-    "strings"
     "time"
 
     "github.com/google/uuid"
@@ -207,6 +206,14 @@ func (e BackendTestEventEvent) gleanEvent() gleanEvent {
     )
 }
 
+func StringListStringify(stringListMetricValue []string) (string, error) {
+    stringListString, err := json.Marshal(stringListMetricValue)
+	if err != nil {
+		return "", err
+	}
+	return string(stringListString), nil
+}
+
 type EventsPingEvent interface {
     isEventsPingEvent()
     gleanEvent() gleanEvent
@@ -228,6 +235,11 @@ func (g GleanEventsLogger) RecordEventsPing(
     requestInfo RequestInfo,
     params EventsPing,
 ) error {
+    MetricRequestStringListString, error := StringListStringify(params.MetricRequestStringList)
+    if error != nil {
+        return error
+    }
+
     metrics := metrics{
         "string": {
             "metric.name": params.MetricName,
@@ -242,7 +254,7 @@ func (g GleanEventsLogger) RecordEventsPing(
             "metric.request_datetime": params.MetricRequestDatetime.Format("2006-01-02T15:04:05.000Z"),
         },
         "string_list": {
-            "metric.request_string_list": strings.Join(params.MetricRequestStringList, ","),
+            "metric.request_string_list": MetricRequestStringListString,
         },
     }
 
@@ -273,6 +285,11 @@ func (g GleanEventsLogger) RecordServerTelemetryScenarioOnePing(
     requestInfo RequestInfo,
     params ServerTelemetryScenarioOnePing,
 ) error {
+    MetricRequestStringListString, error := StringListStringify(params.MetricRequestStringList)
+    if error != nil {
+        return error
+    }
+
     metrics := metrics{
         "string": {
             "metric.name": params.MetricName,
@@ -287,7 +304,7 @@ func (g GleanEventsLogger) RecordServerTelemetryScenarioOnePing(
             "metric.request_datetime": params.MetricRequestDatetime.Format("2006-01-02T15:04:05.000Z"),
         },
         "string_list": {
-            "metric.request_string_list": strings.Join(params.MetricRequestStringList, ","),
+            "metric.request_string_list": MetricRequestStringListString,
         },
     }
 
diff --git a/tests/data/server_events_only_compare.go b/tests/data/server_events_only_compare.go
index 1c4071054..ef2696342 100644
--- a/tests/data/server_events_only_compare.go
+++ b/tests/data/server_events_only_compare.go
@@ -13,7 +13,6 @@ import (
     "fmt"
     "io"
     "strconv"
-    "strings"
     "time"
 
     "github.com/google/uuid"
@@ -207,6 +206,14 @@ func (e BackendTestEventEvent) gleanEvent() gleanEvent {
     )
 }
 
+func StringListStringify(stringListMetricValue []string) (string, error) {
+    stringListString, err := json.Marshal(stringListMetricValue)
+	if err != nil {
+		return "", err
+	}
+	return string(stringListString), nil
+}
+
 type EventsPingEvent interface {
     isEventsPingEvent()
     gleanEvent() gleanEvent
@@ -228,6 +235,11 @@ func (g GleanEventsLogger) RecordEventsPing(
     requestInfo RequestInfo,
     params EventsPing,
 ) error {
+    MetricRequestStringListString, error := StringListStringify(params.MetricRequestStringList)
+    if error != nil {
+        return error
+    }
+
     metrics := metrics{
         "string": {
             "metric.name": params.MetricName,
@@ -242,7 +254,7 @@ func (g GleanEventsLogger) RecordEventsPing(
             "metric.request_datetime": params.MetricRequestDatetime.Format("2006-01-02T15:04:05.000Z"),
         },
         "string_list": {
-            "metric.request_string_list": strings.Join(params.MetricRequestStringList, ","),
+            "metric.request_string_list": MetricRequestStringListString,
         },
     }
 

From 382d118545b1f656125904482635e1fa8ff6793b Mon Sep 17 00:00:00 2001
From: Masha Lifshin <mlifshin@mozilla.com>
Date: Tue, 9 Dec 2025 11:20:26 -0800
Subject: [PATCH 6/7] Don't preprocess the string list metric at all, actually

---
 glean_parser/templates/go_server.jinja2       | 18 +--------------
 tests/data/server_custom_ping_only_compare.go | 15 +------------
 .../server_events_and_custom_ping_compare.go  | 22 ++-----------------
 tests/data/server_events_only_compare.go      | 15 +------------
 4 files changed, 5 insertions(+), 65 deletions(-)

diff --git a/glean_parser/templates/go_server.jinja2 b/glean_parser/templates/go_server.jinja2
index 93616a2fa..b1775d16d 100644
--- a/glean_parser/templates/go_server.jinja2
+++ b/glean_parser/templates/go_server.jinja2
@@ -220,15 +220,6 @@ func (e {{ event|event_type_name }}) gleanEvent() gleanEvent {
 }
 {% endfor %}
 {% endif %}
-
-{# helper function for stringifying string_list type metrics #}
-func StringListStringify(stringListMetricValue []string) (string, error) {
-    stringListString, err := json.Marshal(stringListMetricValue)
-	if err != nil {
-		return "", err
-	}
-	return string(stringListString), nil
-}
 {# struct & methods for submitting pings #}
 {% for ping, metrics_by_type in pings.items() %}
 {% if metrics_by_type['event'] %}
@@ -263,13 +254,6 @@ func (g GleanEventsLogger) Record{{ ping|ping_type_name }}(
     requestInfo RequestInfo,
     params {{ ping|ping_type_name }},
 ) error {
-    {% for metric in metrics_by_type['string_list'] %}
-    {{ metric|metric_argument_name }}String, error := StringListStringify(params.{{ metric|metric_argument_name }})
-    if error != nil {
-        return error
-    }
-    {% endfor %}
-
     metrics := metrics{
     {% for metric_type, metrics in metrics_by_type.items() %}
     {% if metric_type != 'event' %}
@@ -278,7 +262,7 @@ func (g GleanEventsLogger) Record{{ ping|ping_type_name }}(
             {% if metric_type == 'datetime' %}
             "{{ metric|metric_name }}": params.{{ metric|metric_argument_name }}.Format("2006-01-02T15:04:05.000Z"),
             {% elif metric_type == 'string_list' %}
-            "{{ metric|metric_name }}": {{ metric|metric_argument_name }}String,
+            "{{ metric|metric_name }}": params.{{ metric|metric_argument_name }},
             {% else %}
             "{{ metric|metric_name }}": params.{{ metric|metric_argument_name }},
             {% endif %}
diff --git a/tests/data/server_custom_ping_only_compare.go b/tests/data/server_custom_ping_only_compare.go
index 75f48ab52..0d0a095cd 100644
--- a/tests/data/server_custom_ping_only_compare.go
+++ b/tests/data/server_custom_ping_only_compare.go
@@ -206,14 +206,6 @@ func (e BackendSpecialEventEvent) gleanEvent() gleanEvent {
     )
 }
 
-func StringListStringify(stringListMetricValue []string) (string, error) {
-    stringListString, err := json.Marshal(stringListMetricValue)
-	if err != nil {
-		return "", err
-	}
-	return string(stringListString), nil
-}
-
 type ServerTelemetryScenarioOnePingEvent interface {
     isServerTelemetryScenarioOnePingEvent()
     gleanEvent() gleanEvent
@@ -235,11 +227,6 @@ func (g GleanEventsLogger) RecordServerTelemetryScenarioOnePing(
     requestInfo RequestInfo,
     params ServerTelemetryScenarioOnePing,
 ) error {
-    MetricRequestStringListString, error := StringListStringify(params.MetricRequestStringList)
-    if error != nil {
-        return error
-    }
-
     metrics := metrics{
         "string": {
             "metric.name": params.MetricName,
@@ -254,7 +241,7 @@ func (g GleanEventsLogger) RecordServerTelemetryScenarioOnePing(
             "metric.request_datetime": params.MetricRequestDatetime.Format("2006-01-02T15:04:05.000Z"),
         },
         "string_list": {
-            "metric.request_string_list": MetricRequestStringListString,
+            "metric.request_string_list": params.MetricRequestStringList,
         },
     }
 
diff --git a/tests/data/server_events_and_custom_ping_compare.go b/tests/data/server_events_and_custom_ping_compare.go
index 627426df6..c194d3791 100644
--- a/tests/data/server_events_and_custom_ping_compare.go
+++ b/tests/data/server_events_and_custom_ping_compare.go
@@ -206,14 +206,6 @@ func (e BackendTestEventEvent) gleanEvent() gleanEvent {
     )
 }
 
-func StringListStringify(stringListMetricValue []string) (string, error) {
-    stringListString, err := json.Marshal(stringListMetricValue)
-	if err != nil {
-		return "", err
-	}
-	return string(stringListString), nil
-}
-
 type EventsPingEvent interface {
     isEventsPingEvent()
     gleanEvent() gleanEvent
@@ -235,11 +227,6 @@ func (g GleanEventsLogger) RecordEventsPing(
     requestInfo RequestInfo,
     params EventsPing,
 ) error {
-    MetricRequestStringListString, error := StringListStringify(params.MetricRequestStringList)
-    if error != nil {
-        return error
-    }
-
     metrics := metrics{
         "string": {
             "metric.name": params.MetricName,
@@ -254,7 +241,7 @@ func (g GleanEventsLogger) RecordEventsPing(
             "metric.request_datetime": params.MetricRequestDatetime.Format("2006-01-02T15:04:05.000Z"),
         },
         "string_list": {
-            "metric.request_string_list": MetricRequestStringListString,
+            "metric.request_string_list": params.MetricRequestStringList,
         },
     }
 
@@ -285,11 +272,6 @@ func (g GleanEventsLogger) RecordServerTelemetryScenarioOnePing(
     requestInfo RequestInfo,
     params ServerTelemetryScenarioOnePing,
 ) error {
-    MetricRequestStringListString, error := StringListStringify(params.MetricRequestStringList)
-    if error != nil {
-        return error
-    }
-
     metrics := metrics{
         "string": {
             "metric.name": params.MetricName,
@@ -304,7 +286,7 @@ func (g GleanEventsLogger) RecordServerTelemetryScenarioOnePing(
             "metric.request_datetime": params.MetricRequestDatetime.Format("2006-01-02T15:04:05.000Z"),
         },
         "string_list": {
-            "metric.request_string_list": MetricRequestStringListString,
+            "metric.request_string_list": params.MetricRequestStringList,
         },
     }
 
diff --git a/tests/data/server_events_only_compare.go b/tests/data/server_events_only_compare.go
index ef2696342..5e0ad6d2b 100644
--- a/tests/data/server_events_only_compare.go
+++ b/tests/data/server_events_only_compare.go
@@ -206,14 +206,6 @@ func (e BackendTestEventEvent) gleanEvent() gleanEvent {
     )
 }
 
-func StringListStringify(stringListMetricValue []string) (string, error) {
-    stringListString, err := json.Marshal(stringListMetricValue)
-	if err != nil {
-		return "", err
-	}
-	return string(stringListString), nil
-}
-
 type EventsPingEvent interface {
     isEventsPingEvent()
     gleanEvent() gleanEvent
@@ -235,11 +227,6 @@ func (g GleanEventsLogger) RecordEventsPing(
     requestInfo RequestInfo,
     params EventsPing,
 ) error {
-    MetricRequestStringListString, error := StringListStringify(params.MetricRequestStringList)
-    if error != nil {
-        return error
-    }
-
     metrics := metrics{
         "string": {
             "metric.name": params.MetricName,
@@ -254,7 +241,7 @@ func (g GleanEventsLogger) RecordEventsPing(
             "metric.request_datetime": params.MetricRequestDatetime.Format("2006-01-02T15:04:05.000Z"),
         },
         "string_list": {
-            "metric.request_string_list": MetricRequestStringListString,
+            "metric.request_string_list": params.MetricRequestStringList,
         },
     }
 

From 3734e924bd76c7128d2bd016f2728adf8b138014 Mon Sep 17 00:00:00 2001
From: Masha Lifshin <mlifshin@mozilla.com>
Date: Wed, 10 Dec 2025 10:12:14 -0800
Subject: [PATCH 7/7] Clean up redundant if clause

---
 glean_parser/templates/go_server.jinja2 | 2 --
 1 file changed, 2 deletions(-)

diff --git a/glean_parser/templates/go_server.jinja2 b/glean_parser/templates/go_server.jinja2
index b1775d16d..f3ebb1481 100644
--- a/glean_parser/templates/go_server.jinja2
+++ b/glean_parser/templates/go_server.jinja2
@@ -261,8 +261,6 @@ func (g GleanEventsLogger) Record{{ ping|ping_type_name }}(
         {% for metric in metrics %}
             {% if metric_type == 'datetime' %}
             "{{ metric|metric_name }}": params.{{ metric|metric_argument_name }}.Format("2006-01-02T15:04:05.000Z"),
-            {% elif metric_type == 'string_list' %}
-            "{{ metric|metric_name }}": params.{{ metric|metric_argument_name }},
             {% else %}
             "{{ metric|metric_name }}": params.{{ metric|metric_argument_name }},
             {% endif %}
