11package org .togetherjava .tjbot .features .analytics ;
22
3+ import com .fasterxml .jackson .core .JsonProcessingException ;
4+ import com .fasterxml .jackson .databind .ObjectMapper ;
35import org .slf4j .Logger ;
46import org .slf4j .LoggerFactory ;
57
68import org .togetherjava .tjbot .db .Database ;
79import org .togetherjava .tjbot .db .generated .tables .MetricEvents ;
810
11+ import javax .annotation .Nullable ;
12+
913import java .time .Instant ;
14+ import java .util .Map ;
1015import java .util .concurrent .ExecutorService ;
1116import java .util .concurrent .Executors ;
1217
1520 */
1621public final class Metrics {
1722 private static final Logger logger = LoggerFactory .getLogger (Metrics .class );
23+ private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper ();
1824
1925 private final Database database ;
2026
@@ -35,21 +41,40 @@ public Metrics(Database database) {
3541 * @param event the event to save
3642 */
3743 public void count (String event ) {
44+ count (event , Map .of ());
45+ }
46+
47+ /**
48+ * Track an event execution with custom dimensions.
49+ *
50+ * @param event the event to save
51+ * @param dimensions key-value pairs providing additional context for the event
52+ */
53+ public void count (String event , Map <String , String > dimensions ) {
3854 logger .debug ("Counting new record for event: {}" , event );
39- Instant moment = Instant .now ();
40- service .submit (() -> processEvent (event , moment ));
55+ service .submit (() -> processEvent (event , Instant .now (),
56+ dimensions .isEmpty () ? null : serializeDimensions (dimensions )));
57+ }
4158
59+ private static String serializeDimensions (Map <String , String > dimensions ) {
60+ try {
61+ return OBJECT_MAPPER .writeValueAsString (dimensions );
62+ } catch (JsonProcessingException e ) {
63+ throw new IllegalArgumentException ("Failed to serialize dimensions" , e );
64+ }
4265 }
4366
4467 /**
4568 *
4669 * @param event the event to save
4770 * @param happenedAt the moment when the event is dispatched
71+ * @param dimensionsJson optional JSON-serialized dimensions, or null
4872 */
49- private void processEvent (String event , Instant happenedAt ) {
73+ private void processEvent (String event , Instant happenedAt , @ Nullable String dimensionsJson ) {
5074 database .write (context -> context .newRecord (MetricEvents .METRIC_EVENTS )
5175 .setEvent (event )
5276 .setHappenedAt (happenedAt )
77+ .setDimensions (dimensionsJson )
5378 .insert ());
5479 }
5580
0 commit comments