Events
Definition
Cantor Events
are multi-dimensional time-series data points; where each data point has a timestamp (in milliseconds) along with some arbitrary key/value pairs as metadata (where values are strings), some arbitrary key/value pairs as dimensions (where values are doubles), and optionally a byte array payload attached to an event.
An event looks like this:
{
"timestampMillis": 1616011054775,
"metadata": {
"metadataKey1": "a",
"metadataKey2": "b",
"metadataKey3": "c"
},
"dimensions": {
"dimensionsKey1": 0.1,
"dimensionsKey2": 0.2,
"dimensionsKey3": 0.3
},
"payload": "QmFzZTY0IGVuY29kZWQ="
}
HTTP API
To make HTTP calls in local testing environment, use this base URL: http://localhost:8084.
For convenience, you can use Cantor Swagger UI, which comes with your local cantor instance, to compose the full custom URL for your API calls. Full URL to each API endpoint's Swagger UI page is linked on each endpoint below. Remember to spin up your local cantor HTTP server instance before you click on any Swagger UI link on this page.
Most of the Events
API endpoints need required and/or optional URL parameters. Required URL parameters are shown as part of endpoint's path, while optional URL parameters, if existed, are given below. Only one endpoint (i.e. POST /api/events/{namespace}
) needs data parameters.
GET /api/events
Get all event namespaces.
Sample Code:
curl -X GET "http://localhost:8084/api/events" -H "accept: application/json"
GET /api/events/{namespace}
Get all events under a specific namespace.
Optional URL Paramemter(s):
-
start
:integer
UNIX Time.
-
end
:integer
UNIX Time.
-
metadata_query
:string array
There are two kinds of metadata query you can use:
-
exact match, e.g.
["host=localhost"]
matches only the events whose metadata value for metadata keyhost
is exactlylocalhost
-
regex match using
~
and*
, e.g.["host=~prod-*-example"]
matches only the events whose metadata value for metadata keyhost
starts withprod-
and ends with-example
-
-
dimensions_query
:string array
You can also use
=
,<
,<=
,>=
or>
as part of dimensions query, e.g.["cpu>=0.3"]
matches only the events whose dimension value for dimension keycpu
has a value higher than or equal to0.3
. -
include_payloads
:boolean
Defaulted to
false
. Responses will include the payload of the events if set totrue
. -
ascending
:boolean
Defaulted to
true
. Events returned will be sorted in ascending order if set totrue
and vice versa. -
limit
:integer
Defaulted to
0
, which puts no limit on the number of events returned. If specified, this parameter limits the maximum number of events returned.
Sample Code:
This mock HTTP call returns a list of events under namespace test-namespace
between starting timestamp 1616011054000
and ending timestamp 1616011055000
, where alll values for the metadata key host
starts with na4-
(["host=~na4-*"]
) and alll values for the dimension key cpu
is larger than or equal to 0.3 (["cpu>=0.3"]
).
curl -X GET "http://localhost:8084/api/events/test-namespace?start=1616011054000&end=1616011055000&metadata_query=host%3D~na4-%2A&dimensions_query=cpu%3C%3D0.5&ascending=true" -H "accept: application/json"
GET /api/events/{namespace}/metadata/{metadata}
Get all existing metadata values, for an event metadata key, under a specific event namespace.
Optional URL Paramemter(s):
-
start
:integer
UNIX Time.
-
end
:integer
UNIX Time.API
-
metadata_query
:string array
There are two kinds of metadata query you can use:
-
exact match, e.g.
["host=localhost"]
matches only the events whose metadata value for metadata keyhost
is exactlylocalhost
-
regex match using
~
and*
, e.g.["host=~prod-*-example"]
matches only the events whose metadata value for metadata keyhost
starts withprod-
and ends with-example
-
-
dimensions_query
:string array
You can also use
=
,<
,<=
,>=
or>
as part of dimensions query, e.g.["cpu>=0.3"]
matches only the events whose dimension value for dimension keycpu
has a value higher than or equal to0.3
.
Sample Code:
This mock HTTP call returns all possible metadata values for the metadata key os
under namespace test-namespace
, between starting timestamp 1616011054000
and ending timestamp 1616011055000
, with the metadata query ["host=~*-search"]
and dimensions query ["mem<0.8"]
.
curl -X GET "http://localhost:8084/api/events/test-namespace/metadata/os?start=1616011054000&end=1616011055000&metadata_query=host%3D~%2A-search&dimensions_query=mem%3C0.8" -H "accept: application/json"
POST /api/events/{namespace}
Add event(s) under an event namespace.
Data Paramemter(s):
Include events to be added, e.g.
[
{
"timestampMillis": 1616011054774,
"metadata": {
"metadataKey1": "a"
},
"payload": "QmFzZTY0IGVuY29kZWQ="
},
{
"timestampMillis": 1616011054775,
"dimensions": {
"dimensionsKey2": 0.5
}
},
{
"timestampMillis": 1616011054776,
"metadata": {
"metadataKey3": "a"
},
"dimensions": {
"dimensionsKey1": 0.1,
"dimensionsKey3": 0.18
}
}
]
Sample Code:
This mock HTTP call stores an event (schema defined right above) under the event namespace test-namespace
.
curl -X POST "http://localhost:8084/api/events/test-namespace" -H "accept: */*" -H "Content-Type: application/json" -d "[{\"timestampMillis\":1616011054774,\"metadata\":{\"metadataKey1\":\"a\"},\"payload\":\"QmFzZTY0IGVuY29kZWQ=\"},{\"timestampMillis\":1616011054775,\"dimensions\":{\"dimensionsKey2\":0.5}},{\"timestampMillis\":1616011054776,\"metadata\":{\"metadataKey3\":\"a\"},\"dimensions\":{\"dimensionsKey1\":0.1,\"dimensionsKey3\":0.18}}]"
PUT /api/events/{namespace}
Create an event namespace.
Sample Code:
This mock HTTP call adds the event namespace test-namespace
.
curl -X PUT "http://localhost:8084/api/events/test-namespace" -H "accept: */*"
DELETE /api/events/{namespace}
Drop an event namespace.
Sample Code:
This mock HTTP call drops the event namespace test-namespace
.
curl -X DELETE "http://localhost:8084/api/events/test-namespace" -H "accept: */*"
DELETE /api/events/expire/{namespace}/{endTimestampMillis}
Expire old events under a specific event namespace before the given timestamp.
Sample Code:
This mock HTTP call sets all events under the event namespace test-namespace
to expire before UNIX time 1616020000
, which is March 17, 2021, at 8:43pm in UTC.
curl -X DELETE "http://localhost:8084/api/events/expire/test-namespace/1616020000" -H "accept: */*"
Java gRPC API
To make use of Cantor's gRPC client in local testing environment, make sure you have a local cantor gRPC server instance running.
namespaces()
Get all event namespaces.
Method Signature(s):
Collection<String> namespaces() throws IOException
Sample Code:
import com.salesforce.cantor.grpc.CantorOnGrpc;
import java.io.IOException;
class Scratch {
public static void main(String[] args) throws IOException {
CantorOnGrpc cantor = new CantorOnGrpc("localhost:7443");
System.out.println(cantor.events().namespace());
}
}
create()
Create an event namespace.
Method Signature(s):
void create(String namespace) throws IOException
Sample Code:
This following code creates an event namespace dev-namespace
.
import com.salesforce.cantor.grpc.CantorOnGrpc;
import java.io.IOException;
class Scratch {
public static void main(String[] args) throws IOException {
CantorOnGrpc cantor = new CantorOnGrpc("localhost:7443");
cantor.events().create("dev-namespace");
}
}
store()
Add event(s) under an event namespace.
Method Signature(s):
For storing a single event:
-
void store(String namespace, Event event) throws IOException
-
void store(String namespace, long timestampMillis, Map<String, String> metadata, Map<String, Double> dimensions) throws IOException
-
void store(String namespace, long timestampMillis, Map<String, String> metadata, Map<String, Double> dimensions, byte[] payload) throws IOException
For storing multiple events:
void store(String namespace, Collection<Event> batch) throws IOException
Sample Code:
This following code stores a single event (with metadata, dimensions and payload) under event namespace dev-namespace
.
import com.salesforce.cantor.grpc.CantorOnGrpc;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
class Scratch {
public static void main(String[] args) throws IOException {
CantorOnGrpc cantor = new CantorOnGrpc("localhost:7443");
// remember to create the event namespace first
cantor.events().store("dev-namespace", System.currentTimeMillis(), Collections.singletonMap("metadataKey1", "testValue"), Collections.singletonMap("dimensionsKey2", 5.9), "Hello!".getBytes(StandardCharsets.UTF_8));
}
}
get()
Get all events under a specific namespace.
Argument(s):
-
startTimestampMillis
: Start timestamp in UNIX time. -
endTimestampMillis
: End timestamp in UNIX time. -
metadataQuery
: There are two kinds of metadata query you can use:-
exact match, e.g.
Collections.singletonMap("host", "=localhost")
matches only the events whose metadata value for metadata key host is exactly localhost -
regex match using
~
and*
, e.g.Collections.singletonMap("host", "=~prod-*-example")
matches only the events whose metadata value for metadata keyhost
starts withprod-
and ends with-example
-
-
dimensionsQuery
: You can also use=
,<
,<=
,>=
or>
as part of dimensions query, e.g. aCollections.singletonMap("cpu", >=0.3")
matches only the events whose dimension value for dimension keycpu
has a value higher than or equal to0.3
. -
includePayloads
: Defaulted tofalse
. Responses will include the payload of the events if set totrue
. -
ascending
: Defaulted totrue
. Events returned will be sorted in ascending order if set totrue
and vice versa. -
limit
: Defaulted to0
, which puts no limit on the number of events returned. If specified, this parameter limits the maximum number of events returned.
Method Signature(s):
List<Event> get(String namespace,
long startTimestampMillis,
long endTimestampMillis) throws IOException
List<Event> get(String namespace,
long startTimestampMillis,
long endTimestampMillis,
boolean includePayloads) throws IOException
List<Event> get(String namespace,
long startTimestampMillis,
long endTimestampMillis,
Map<String, String> metadataQuery,
Map<String, String> dimensionsQuery) throws IOException
List<Event> get(String namespace,
long startTimestampMillis,
long endTimestampMillis,
Map<String, String> metadataQuery,
Map<String, String> dimensionsQuery,
boolean includePayloads) throws IOException
List<Event> get(String namespace,
long startTimestampMillis,
long endTimestampMillis,
Map<String, String> metadataQuery,
Map<String, String> dimensionsQuery,
boolean includePayloads,
boolean ascending,
int limit) throws IOException
Sample Code:
import com.salesforce.cantor.grpc.CantorOnGrpc;
import java.io.IOException;
class Scratch {
public static void main(String[] args) throws IOException {
CantorOnGrpc cantor = new CantorOnGrpc("localhost:7443");
System.out.println(cantor.events().get("dev-namespace", System.currentTimeMillis() - 60000, System.currentTimeMillis(), false));
}
}
metadata()
Get distinct metadata values for the given metadata key for events in the given namespace, with timestamp between
the startTimestampMillis
and endTimestampMillis
, metadata and dimensions matching the given queries(metadataQuery
and dimensionsQuery
).
Method Signature(s):
Set<String> metadata(String namespace,
String metadataKey,
long startTimestampMillis,
long endTimestampMillis,
Map<String, String> metadataQuery,
Map<String, String> dimensionsQuery) throws IOException
Sample Code:
import com.salesforce.cantor.grpc.CantorOnGrpc;
import java.io.IOException;
import java.util.Collections;
class Scratch {
public static void main(String[] args) throws IOException {
CantorOnGrpc cantor = new CantorOnGrpc("localhost:7443");
System.out.println(cantor.events().metadata("dev-namespace", 0, System.currentTimeMillis(), Collections.singletonMap("metadataKey1", "=~test*"), null));
}
}
drop()
Drop an event namespace.
Method Signature(s):
void drop(String namespace) throws IOException
Sample Code:
import com.salesforce.cantor.grpc.CantorOnGrpc;
import java.io.IOException;
class Scratch {
public static void main(String[] args) throws IOException {
CantorOnGrpc cantor = new CantorOnGrpc("localhost:7443");
cantor.events().drop("dev-namespace");
}
}
expire()
Expire all events with timestamp before the given end timestamp.
Method Signature(s):
void expire(String namespace, long endTimestampMillis)
Sample Code:
import com.salesforce.cantor.grpc.CantorOnGrpc;
import java.io.IOException;
class Scratch {
public static void main(String[] args) throws IOException {
CantorOnGrpc cantor = new CantorOnGrpc("localhost:7443");
cantor.events().expire("dev-namespace", 1616031010483);
}
}
Use Case
Any time-series data fits will as a use case for events. Keep a log of requests to your web-service, with query parameters and headers as metadata. Add response size, request latency, and number of errors as dimensions. You could even store the response body as a payload. Metadata and dimension keys do not have to be defined beforehand, so new keys can crop up at runtime without needing to change any schema or config.