Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>fi.hsl</groupId>
<artifactId>transitdata-common</artifactId>
<version>3.1.0</version>
<version>3.2.0</version>
<packaging>jar</packaging>
<name>Common utilities for Transitdata projects</name>

Expand Down
54 changes: 54 additions & 0 deletions src/main/java/fi/hsl/common/metrics/PipelineMetrics.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package fi.hsl.common.metrics;

import fi.hsl.common.transitdata.TransitdataProperties;
import io.prometheus.client.Histogram;
import org.apache.pulsar.client.api.Message;
import org.apache.pulsar.client.api.TypedMessageBuilder;

public final class PipelineMetrics {

Expand All @@ -25,4 +28,55 @@ public static void observeLatency(final String pipeline, final double seconds) {
public static void observePublishDuration(final String pipeline, final double seconds) {
PUBLISH_DURATION.labels(pipeline).observe(seconds);
}

/**
* Resolve the pipeline-ingress timestamp (epoch ms) for a message being produced: forwarded from the incoming
* message's source timestamp when present, otherwise the current time. Pass null for a source component that has
* no incoming Pulsar message.
*/
public static long resolveSourceTimestampMs(final Message<?> incoming) {
if (incoming != null) {
final String raw = incoming.getProperty(TransitdataProperties.KEY_SOURCE_MESSAGE_TIMESTAMP_MS);
if (raw != null && !raw.isEmpty()) {
try {
return Long.parseLong(raw);
} catch (final NumberFormatException ignored) {
// malformed value, fall through to current time
}
}
}
return System.currentTimeMillis();
}

/**
* Stamp the pipeline-ingress (source) timestamp on an outgoing message so it propagates through the pipeline. The
* first producer in a chain stamps the current time; downstream stages forward the value unchanged. Pass the
* incoming message to forward, or null at a source component.
*/
public static void stampSourceTimestamp(final TypedMessageBuilder<?> out, final Message<?> incoming) {
out.property(TransitdataProperties.KEY_SOURCE_MESSAGE_TIMESTAMP_MS,
String.valueOf(resolveSourceTimestampMs(incoming)));
}

/**
* Observe pipeline latency as now minus the message's source (pipeline-ingress) timestamp. No observation is
* recorded when the message carries no valid source timestamp.
*/
public static void observeLatencyFromSource(final String pipeline, final Message<?> message) {
if (message == null) {
return;
}
final String raw = message.getProperty(TransitdataProperties.KEY_SOURCE_MESSAGE_TIMESTAMP_MS);
if (raw == null || raw.isEmpty()) {
return;
}
try {
final long sourceTs = Long.parseLong(raw);
if (sourceTs > 0) {
observeLatency(pipeline, (System.currentTimeMillis() - sourceTs) / 1000.0);
}
} catch (final NumberFormatException ignored) {
// no observation for malformed timestamp
}
}
}
Loading