-
Notifications
You must be signed in to change notification settings - Fork 3.8k
feat: Add now() to troubleshoot pipeline latencies
#19386
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
3ab8079
7e691f3
69083f1
8557ca9
8fa6a6d
4297baa
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -110,6 +110,7 @@ The following built-in functions are available. | |
|
|
||
| |name|description| | ||
| |----|-----------| | ||
| |now|now() returns the current system timestamp in milliseconds since epoch (1970-01-01 00:00:00 UTC). This function is evaluated for each row at processing time. It's recommended to use this only for troubleshooting issues - see [Using now() in ingestion](#using-now-in-ingestion).| | ||
| |timestamp|timestamp(expr[,format-string]) parses string expr into date then returns milliseconds from java epoch. without 'format-string' it's regarded as ISO datetime format | | ||
| |unix_timestamp|same with 'timestamp' function but returns seconds instead | | ||
| |timestamp_ceil|timestamp_ceil(expr, period, \[origin, \[timezone\]\]) rounds up a timestamp, returning it as a new timestamp. Period can be any ISO8601 period, like P3M (quarters) or PT12H (half-days). The time zone, if provided, should be a time zone name like "America/Los_Angeles" or offset like "-08:00".| | ||
|
|
@@ -119,6 +120,26 @@ The following built-in functions are available. | |
| |timestamp_parse|timestamp_parse(string expr, \[pattern, [timezone\]\]) parses a string into a timestamp using a given [Joda DateTimeFormat pattern](http://www.joda.org/joda-time/apidocs/org/joda/time/format/DateTimeFormat). If the pattern is not provided, this parses time strings in either ISO8601 or SQL format. The time zone, if provided, should be a time zone name like "America/Los_Angeles" or offset like "-08:00", and will be used as the time zone for strings that do not include a time zone offset. Pattern and time zone must be literals. Strings that cannot be parsed as timestamps will be returned as nulls.| | ||
| |timestamp_format|timestamp_format(expr, \[pattern, \[timezone\]\]) formats a timestamp as a string with a given [Joda DateTimeFormat pattern](http://www.joda.org/joda-time/apidocs/org/joda/time/format/DateTimeFormat), or ISO8601 if the pattern is not provided. The time zone, if provided, should be a time zone name like "America/Los_Angeles" or offset like "-08:00". Pattern and time zone must be literals.| | ||
|
|
||
| ### Using `now()` in ingestion | ||
|
|
||
| :::warning | ||
| `now()` is non-deterministic: replicated streaming tasks and task replays evaluate it to different | ||
| values, producing inconsistent results across replicas. Do not use `now()` to overwrite `__time`. | ||
| For Kafka, prefer [`kafka.timestamp`](../ingestion/data-formats.md#kafka) as the | ||
| `__time` source. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure if it makes sense to mention Kafka here. The timestamps aren't equivalent as one is the time the event lands on Kafka and the other is the time the event is ingested in Druid |
||
| ::: | ||
|
|
||
| To troubleshoot end-to-end pipeline delays, store `now() - __time` as a separate dimension via a | ||
| [`transformSpec`](../ingestion/ingestion-spec.md#transformspec): | ||
|
|
||
| ```json | ||
| "transformSpec": { | ||
| "transforms": [ | ||
| { "type": "expression", "name": "ingestion_lag_ms", "expression": "now() - __time" } | ||
| ] | ||
| } | ||
| ``` | ||
|
|
||
| ## Math functions | ||
|
|
||
| See javadoc of java.lang.Math for detailed explanation for each function. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -214,4 +214,95 @@ public Object getLiteralValue() | |
| } | ||
| } | ||
|
|
||
| /** | ||
| * Expression macro for now() function that returns current system timestamp. | ||
| * Implemented as a macro to prevent constant folding optimization. | ||
| */ | ||
| public static class NowExprMacro implements ExprMacroTable.ExprMacro | ||
| { | ||
| public static final String NAME = "now"; | ||
|
|
||
| @Override | ||
| public String name() | ||
| { | ||
| return NAME; | ||
| } | ||
|
|
||
| @Override | ||
| public Expr apply(List<Expr> args) | ||
| { | ||
| validationHelperCheckArgumentCount(args, 0); | ||
| return new NowExpression(); | ||
| } | ||
|
|
||
| static final class NowExpression implements Expr | ||
| { | ||
| @Override | ||
| public ExprEval eval(ObjectBinding bindings) | ||
| { | ||
| return ExprEval.ofLong(System.currentTimeMillis()); | ||
| } | ||
|
|
||
| @Override | ||
| public String stringify() | ||
| { | ||
| return "now()"; | ||
| } | ||
|
|
||
| @Override | ||
| public Expr visit(Shuttle shuttle) | ||
| { | ||
| return shuttle.visit(this); | ||
| } | ||
|
|
||
| @Override | ||
| public BindingAnalysis analyzeInputs() | ||
| { | ||
| // Return analysis indicating this is NOT constant | ||
| // by pretending we have a free variable | ||
| return new BindingAnalysis(); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [P2] Prevent now() from being planned as constant Returning an empty BindingAnalysis makes ExpressionPlanner mark now() and expressions that only depend on now() as CONSTANT. Query-time expression selectors then build a ConstantExprEvalSelector and evaluate now() once when the selector is created, and expression filters/virtual columns also get stable cache keys, so native queries can reuse stale timestamps instead of evaluating at processing time. Add explicit non-deterministic handling, or otherwise keep now() out of constant selector/index/cache optimizations. |
||
| } | ||
|
|
||
| @Nullable | ||
| @Override | ||
| public ExpressionType getOutputType(InputBindingInspector inspector) | ||
| { | ||
| return ExpressionType.LONG; | ||
| } | ||
|
|
||
| @Override | ||
| public boolean isLiteral() | ||
| { | ||
| // NOT a literal - prevents constant folding | ||
| return false; | ||
| } | ||
|
|
||
| @Override | ||
| public boolean isNullLiteral() | ||
| { | ||
| return false; | ||
| } | ||
|
|
||
| @Nullable | ||
| @Override | ||
| public Object getLiteralValue() | ||
| { | ||
| // Not a literal, so no constant value | ||
| return null; | ||
| } | ||
|
|
||
| @Override | ||
| public int hashCode() | ||
| { | ||
| return NowExpression.class.hashCode(); | ||
| } | ||
|
|
||
| @Override | ||
| public boolean equals(Object obj) | ||
| { | ||
| return obj instanceof NowExpression; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just for consistency with other functions