Is there a way to send custom metrics in RUM without having to wrap a transaction with .start() and .end()?
The use case here is that we are capturing and computing our own metrics asynchronously (for example, regular beacon calls to a server, which we aggregate into an average) and we'd like to send that data as maybe a single call to .sendMetric(metricObject) pre-decorated with our own context info like transaction name and type.
Our workaround at the moment is to contain our custom timings inside a transaction as tags, but not sure if this is really very efficient in the long run, and what the implications are with ECS moving forward.
Unfortunately it's not possible to to send custom metrics on their own to the APM server, at the moment. I've created an issue for this feature request.
To better understand your use-case, would you please provide some examples of the metrics you would like to capture?
So for RUM usage, we basically have the normal page load and transactions. I would define transactions as something normally user-initiated or triggered. It makes sense to wrap a transaction flow in between a .startTransaction() and a transaction.end() and let the RUM agent take care of all the data collection and enrichment.
However, there are sometimes use cases where we'd like RUM metric for non-user triggered events. As an example, we have a web page used by back office operators that displays the number of open tickets that get updated every 60 seconds via an XMLHttpRequest. It also displays other data requested by other XMLHttpRequests at regular intervals or event-triggered. These pages rarely get refreshed or closed. We have an internal instrumentation that measures the request time, and captures the result for each of these roundtrips then stores these in an array. We'd like to have a way to send those collected instrumentation data to the APM server via a single .sendMetrics(object) on our own pre-determined triggers, each metric object can be something like an array of {"transaction.name":"transaction_name","transaction.duration":duration_in_microseconds,"transaction.type":"some_transaction_type"} . We do not see the need of having to wrap those metrics in a .startTransaction()-.end() transaction. At the moment, we have to put those in tags and then create a way to handle those tags into transactions.
Thanks for the detailed explanation. As Hamid pointed out, we currently don't have support for sending Custom Metrics even though our APM server has support for custom metric sets.
We actually thought about using that but are wary because there might be changes in the future that could possibly break our implementation (say, changes in the API field names or schema, etc). We still might decide to do it if the current available features prove inadequate, so having the agent handle it definitely makes for a future-proof (and ECS compliant) implementation
The pattern we were looking at is the old Boomerangjs RUM agent originally created by Yahoo which had BOOMR.sendMetrics(metrics) which can be used like
// send multiple metrics at once
BOOMR.sendMetrics({
"MyMetric": 2,
"MyOtherMetric": 1
});
This approach is useful in situations where
Custom instrumentation exists and all we need to do is send the metrics to the APM Server
Multiple transactions are happening at once. Since Elastic APM can only handle one transaction at a time, leaving the web app to compute various transactions on its own and using APM server as just a unified collector. It is also less costly as we do not need to create multiple .startTransaction()/transaction.end() envelops for each custom metric set.
Sorry for the confusion, When I brought up the schema of the APM-Server, I forgot to mention that our public facing user API would indeed transform the values passed and convert the object to whatever format APM server expects.
As far as I read your concern, you would be able to do in the same pattern and our API would look roughly like this
const metricsObj = {
'metric-a': 10,
'metric-b': 20
}
/**
* Custom tags that can provide useful information on the metrics itself
*/
const optionalTags = {
'transaction-name': 'custom',
'url': 'blah'
}
// send the metrics to Server every 10 seconds or in your case on every XHR request
setInterval(() => {
sendMetrics(metricsObj, optionalTags)
}, 10000)
This would not add any transaction related data just the metrics sets.
Apache, Apache Lucene, Apache Hadoop, Hadoop, HDFS and the yellow elephant
logo are trademarks of the
Apache Software Foundation
in the United States and/or other countries.