<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>Elastic Observability Labs - Articles by Nicolas Ruflin</title>
        <link>https://www.elastic.co/observability-labs</link>
        <description>Trusted security news &amp; research from the team at Elastic.</description>
        <lastBuildDate>Mon, 08 Jun 2026 15:18:17 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>Elastic Observability Labs - Articles by Nicolas Ruflin</title>
            <url>https://www.elastic.co/observability-labs/assets/observability-labs-thumbnail.png</url>
            <link>https://www.elastic.co/observability-labs</link>
        </image>
        <copyright>© 2026. Elasticsearch B.V. All Rights Reserved</copyright>
        <item>
            <title><![CDATA[How to use Elasticsearch and Time Series Data Streams for observability metrics]]></title>
            <link>https://www.elastic.co/observability-labs/blog/time-series-data-streams-observability-metrics</link>
            <guid isPermaLink="false">time-series-data-streams-observability-metrics</guid>
            <pubDate>Thu, 04 May 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[With Time Series Data Streams (TSDS), Elasticsearch introduces optimized storage for metrics time series. Check out how we use it for Elastic Observability.]]></description>
            <content:encoded><![CDATA[<p>Elasticsearch is used for a wide variety of data types — one of these is metrics. With the introduction of Metricbeat many years ago and later our APM Agents, the metric use case has become more popular. Over the years, Elasticsearch has made many improvements on how to handle things like metrics aggregations and sparse documents. At the same time, <a href="https://www.elastic.co/guide/en/kibana/current/tsvb.html">TSVB visualizations</a> were introduced to make visualizing metrics easier. One concept that was missing that exists for most other metric solutions is the concept of time series with dimensions.</p>
<p>Mid 2021, the Elasticsearch team <a href="https://github.com/elastic/elasticsearch/issues/74660">embarked</a> on making Elasticsearch a much better fit for metrics. The team created <a href="https://www.elastic.co/guide/en/elasticsearch/reference/master/tsds.html">Time Series Data Streams (TSDS)</a>, which were released in 8.7 as generally available (GA).</p>
<p>This blog post dives into how TSDS works and how we use it in Elastic Observability, as well as how you can use it for your own metrics.</p>
<h2>A quick introduction to TSDS</h2>
<p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/master/tsds.html">Time Series Data Streams (TSDS)</a> are built on top of data streams in Elasticsearch that are optimized for time series. To create a data stream for metrics, an additional setting on the data stream is needed. As we are using data streams, first an Index Template has to be created:</p>
<pre><code class="language-json">PUT _index_template/metrics-laptop
{
  &quot;index_patterns&quot;: [
    &quot;metrics-laptop-*&quot;
  ],
  &quot;data_stream&quot;: {},
  &quot;priority&quot;: 200,
  &quot;template&quot;: {
    &quot;settings&quot;: {
      &quot;index.mode&quot;: &quot;time_series&quot;
    },
    &quot;mappings&quot;: {
      &quot;properties&quot;: {
        &quot;host.name&quot;: {
          &quot;type&quot;: &quot;keyword&quot;,
          &quot;time_series_dimension&quot;: true
        },
        &quot;packages.sent&quot;: {
          &quot;type&quot;: &quot;integer&quot;,
          &quot;time_series_metric&quot;: &quot;counter&quot;
        },
        &quot;memory.usage&quot;: {
          &quot;type&quot;: &quot;double&quot;,
          &quot;time_series_metric&quot;: &quot;gauge&quot;
        }
      }
    }
  }
}
</code></pre>
<p>Let's have a closer look at this template. On the top part, we mark the index pattern with metrics-laptop-*. Any pattern can be selected, but it is recommended to use the <a href="https://www.elastic.co/blog/an-introduction-to-the-elastic-data-stream-naming-scheme">data stream naming scheme</a> for all your metrics. The next section sets the &quot;index.mode&quot;: &quot;time_series&quot; in combination with making sure it is a data_stream: &quot;data_stream&quot;: {}.</p>
<h3>Dimensions</h3>
<p>Each time series data stream needs at least one dimension. In the example above, host.name is set as a dimension field with &quot;time_series_dimension&quot;: true. You can have up to 16 dimensions by default. Not every dimension must show up in each document. The dimensions define the time series. The general rule is to pick fields as dimensions that uniquely identify your time series. Often this is a unique description of the host/container, but for some metrics like disk metrics, the disk id is needed in addition. If you are curious about default recommended dimensions, have a look at this <a href="https://github.com/elastic/ecs/pull/2172">ECS contribution</a> with dimension properties.</p>
<h2>Reduced storage and increased query speed</h2>
<p>At this point, you already have a functioning time series data stream. Setting the index mode to time series automatically turns on <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-source-field.html#synthetic-source">synthetic source</a>. By default, Elasticsearch typically duplicates data three times:</p>
<ul>
<li><a href="https://en.wikipedia.org/wiki/Column-oriented_DBMS#Row-oriented_systems">row-oriented storage</a> (_source field)</li>
<li><a href="https://en.wikipedia.org/wiki/Column-oriented_DBMS#Column-oriented_systems">column-oriented storage</a> (doc_values: true for aggregations)</li>
<li>indices (index: true for filtering and search)</li>
</ul>
<p>With synthetic source, the _source field is not persisted; instead, it is reconstructed from the doc values. Especially in the metrics use case, there are little benefits to keeping the source.</p>
<p>Not storing it means a significant reduction in storage. Time series data streams sort the data based on the dimensions and the time stamp. This means data that is usually queried together is stored together, which speeds up query times. It also means that the data points for a single time series are stored alongside each other on disk. This enables further compression of the data as the rate at which a counter increases is often relatively constant.</p>
<h2>Metric types</h2>
<p>But to benefit from all the advantages of TSDS, the field properties of the metrics fields must be extended with the <code>time_series_metric: {type}</code>. Several <a href="https://www.elastic.co/guide/en/elasticsearch/reference/master/tsds.html#time-series-metric">types are supported</a> — as an example, gauge and counter were used above. Giving Elasticsearch knowledge about the metric type allows Elasticsearch to offer more optimized queries for the different types and reduce storage usage further.</p>
<p>When you create your own templates for data streams under the <a href="https://www.elastic.co/blog/an-introduction-to-the-elastic-data-stream-naming-scheme">data stream naming scheme</a>, it is important that you set &quot;priority&quot;: 200 or higher, as otherwise the built-in default template will apply.</p>
<h2>Ingest a document</h2>
<p>Ingesting a document into a TSDS isn't in any way different from ingesting documents into Elasticsearch. You can use the following commands in Dev Tools to add a document, and then search for it and also check out the mappings. Note: You have to adjust the @timestamp field to be close to your current date and time.</p>
<pre><code class="language-bash"># Add a document with `host.name` as the dimension
POST metrics-laptop-default/_doc
{
  # This timestamp neesd to be adjusted to be current
  &quot;@timestamp&quot;: &quot;2023-03-30T12:26:23+00:00&quot;,
  &quot;host.name&quot;: &quot;ruflin.com&quot;,
  &quot;packages.sent&quot;: 1000,
  &quot;memory.usage&quot;: 0.8
}

# Search for the added doc, _source will show up but is reconstructed
GET metrics-laptop-default/_search

# Check out the mappings
GET metrics-laptop-default
</code></pre>
<p>If you do search, it still shows _source but this is reconstructed from the doc values. The additional field added above is @timestamp. This is important as it is a required field for any data stream.</p>
<h2>Why is this all important for Observability?</h2>
<p>One of the advantages of the Elastic Observability solution is that in a single storage engine, all signals are brought together in a single place. Users can query logs, metrics, and traces together without having to jump from one system to another. Because of this, having a great storage and query engine not only for logs but also metrics is key for us.</p>
<h2>Usage of TSDS in integrations</h2>
<p>With <a href="https://www.elastic.co/integrations/data-integrations">integrations</a>, we give our users an out of the box experience to integrate with their infrastructure and services. If you are using our integrations, eventually you will automatically get all the benefits of TSDS for your metrics assuming you are on version 8.7 or newer.</p>
<p>Currently we are working through the list of our integration packages, add the dimensions, metric type fields and then turn on TSDS for the metrics data streams. What this means is as soon as the package has all properties enabled, the only thing you have to do is upgrade the integration and everything else will happen automatically in the background.</p>
<p>To visualize your time series in Kibana, use <a href="https://www.elastic.co/guide/en/kibana/current/lens.html">Lens</a>, which has native support built in for TSDS.</p>
<h2>Learn more</h2>
<p>If you switch over to TSDS, you will automatically benefit from all the future improvements Elasticsearch is making for metrics time series, be it more efficient storage, query performance, or new aggregation capabilities. If you want to learn more about how TSDS works under the hood and all available config options, check out the <a href="https://www.elastic.co/guide/en/elasticsearch/reference/master/tsds.html">TSDS documentation</a>. What Elasticsearch supports in 8.7 is only the first iteration of the metrics time series in Elasticsearch.</p>
<p><a href="https://www.elastic.co/blog/whats-new-elasticsearch-8-7-0">TSDS can be used since 8.7</a> and will be in more and more of our integrations automatically when integrations are upgraded. All you will notice is lower storage usage and faster queries. Enjoy!</p>
]]></content:encoded>
            <category>observability-labs</category>
            <enclosure url="https://www.elastic.co/observability-labs/assets/images/time-series-data-streams-observability-metrics/ebpf-monitoring.jpeg" length="0" type="image/jpeg"/>
        </item>
        <item>
            <title><![CDATA[Simplifying log data management: Harness the power of flexible routing with Elastic]]></title>
            <link>https://www.elastic.co/observability-labs/blog/simplifying-log-data-management-flexible-routing</link>
            <guid isPermaLink="false">simplifying-log-data-management-flexible-routing</guid>
            <pubDate>Tue, 13 Jun 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[The reroute processor, available as of Elasticsearch 8.8, allows customizable rules for routing documents, such as logs, into data streams for better control of processing, retention, and permissions with examples that you can try on your own.]]></description>
            <content:encoded><![CDATA[<p>In Elasticsearch 8.8, we’re introducing the <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/reroute-processor.html">reroute processor</a> in technical preview that makes it possible to send documents, such as logs, to different <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/data-streams.html">data streams</a>, according to flexible routing rules. When using Elastic Observability, this gives you more granular control over your data with regard to retention, permissions, and processing with all the potential benefits of the <a href="https://www.elastic.co/blog/an-introduction-to-the-elastic-data-stream-naming-scheme">data stream naming scheme</a>. While optimized for data streams, the reroute processor also works with classic indices. This blog post contains examples on how to use the reroute processor that you can try on your own by executing the snippets in the <a href="https://www.elastic.co/guide/en/kibana/current/console-kibana.html">Kibana dev tools</a>.</p>
<p>Elastic Observability offers a wide range of <a href="https://www.elastic.co/integrations/data-integrations?solution=observability">integrations</a> that help you to monitor your applications and infrastructure. These integrations are added as policies to <a href="https://www.elastic.co/guide/en/fleet/current/elastic-agent-installation.html">Elastic agents</a>, which help ingest telemetry into Elastic Observability. Several examples of these integrations include the ability to ingest logs from systems that send a stream of logs from different applications, such as <a href="https://www.elastic.co/guide/en/kinesis/current/aws-firehose-setup-guide.html">Amazon Kinesis Data Firehose</a>, <a href="https://docs.elastic.co/en/integrations/kubernetes">Kubernetes container logs</a>, and <a href="https://docs.elastic.co/integrations/tcp">syslog</a>. One challenge is that these multiplexed log streams are sending data to the same Elasticsearch data stream, such as logs-syslog-default. This makes it difficult to create parsing rules in ingest pipelines and dashboards for specific technologies, such as the ones from the <a href="https://docs.elastic.co/en/integrations/nginx">Nginx</a> and <a href="https://docs.elastic.co/en/integrations/apache">Apache</a> integrations. That’s because in Elasticsearch, in combination with the <a href="https://www.elastic.co/blog/an-introduction-to-the-elastic-data-stream-naming-scheme">data stream naming scheme</a>, the processing and the schema are both encapsulated in a data stream.</p>
<p>The reroute processor helps you tease apart data from a generic data stream and send it to a more specific one. You may use that mechanism to send logs to a data stream that is set up by the Nginx integration, for example, so that the logs are parsed with that integration and you can use the integration’s prebuilt dashboards or create custom ones with the fields, such as the url, the status code, and the response time that the Nginx pipeline has parsed out of the Nginx log message. You can also split out/separate regular Nginx logs and errors with the reroute processor, providing further separation ability and categorization of logs.</p>
<p><img src="https://www.elastic.co/observability-labs/assets/images/simplifying-log-data-management-flexible-routing/blog-elastic-routing-pipeline.png" alt="routing pipeline" /></p>
<h2>Example use case</h2>
<p>To use the reroute processor, first:</p>
<ol>
<li>
<p>Ensure you are on Elasticsearch 8.8</p>
</li>
<li>
<p>Ensure you have permissions to manage indices and data streams</p>
</li>
<li>
<p>If you don’t already have an account on <a href="https://cloud.elastic.co/registration?fromURI=/home">Elastic Cloud</a>, sign up for one</p>
</li>
</ol>
<p>Next, you’ll need to <a href="https://www.elastic.co/guide/en/elasticsearch/reference/master/set-up-a-data-stream.html">set up a data stream</a> and create a custom Elasticsearch <a href="https://www.elastic.co/guide/en/elasticsearch/reference/master/ingest.html">ingest pipeline</a> that is called as the <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/ingest.html#set-default-pipeline">default pipeline</a>. Below we go through this step by step for the “mydata” data set that we’ll simulate ingesting container logs into. We start with a basic example and extend it from there.</p>
<p>The following steps should be utilized in the Elastic console, which is found at <strong>Management -&gt; Dev tools -&gt; Console</strong>. First, we need an an ingest pipeline and a template for the data stream:</p>
<pre><code class="language-bash">PUT _ingest/pipeline/logs-mydata
{
  &quot;description&quot;: &quot;Routing for mydata&quot;,
  &quot;processors&quot;: [
    {
      &quot;reroute&quot;: {
      }
    }
  ]
}
</code></pre>
<p>This creates an ingest pipeline with an empty reroute processor. To make use of it, we need an index template:</p>
<pre><code class="language-bash">PUT _index_template/logs-mydata
{
  &quot;index_patterns&quot;: [
    &quot;logs-mydata-*&quot;
  ],
  &quot;data_stream&quot;: {},
  &quot;priority&quot;: 200,
  &quot;template&quot;: {
    &quot;settings&quot;: {
      &quot;index.default_pipeline&quot;: &quot;logs-mydata&quot;
    },
    &quot;mappings&quot;: {
      &quot;properties&quot;: {
        &quot;container.name&quot;: {
          &quot;type&quot;: &quot;keyword&quot;
        }
      }
    }
  }
}
</code></pre>
<p>The above template is applied to all data that is shipped to logs-mydata-*. We have mapped container.name as a keyword, as this is the field we will be using for routing later on. Now, we send a document to the data stream and it will be ingested into logs-mydata-default:</p>
<pre><code class="language-bash">POST logs-mydata-default/_doc
{
  &quot;@timestamp&quot;: &quot;2023-05-25T12:26:23+00:00&quot;,
  &quot;container&quot;: {
    &quot;name&quot;: &quot;foo&quot;
  }
}
</code></pre>
<p>We can check that it was ingested with the command below, which will show 1 result.</p>
<pre><code class="language-bash">GET logs-mydata-default/_search
</code></pre>
<p>Without modifying the routing processor, this already allows us to route documents. As soon as the reroute processor is specified, it will look for data_stream.dataset and data_stream.namespace fields by default and will send documents to the corresponding data stream, according to the <a href="https://www.elastic.co/blog/an-introduction-to-the-elastic-data-stream-naming-scheme">data stream naming scheme</a> logs-&lt;dataset&gt;-&lt;namespace&gt;. Let’s try this out:</p>
<pre><code class="language-bash">POST logs-mydata-default/_doc
{
  &quot;@timestamp&quot;: &quot;2023-03-30T12:27:23+00:00&quot;,
  &quot;container&quot;: {
&quot;name&quot;: &quot;foo&quot;
  },
  &quot;data_stream&quot;: {
    &quot;dataset&quot;: &quot;myotherdata&quot;
  }
}
</code></pre>
<p>As can be seen with the GET logs-mydata-default/_search command, this document ended up in the logs-myotherdata-default data stream. But instead of using default rules, we want to create our own rules for the field container.name. If the field is container.name = foo, we want to send it to logs-foo-default. For this we modify our routing pipeline:</p>
<pre><code class="language-bash">PUT _ingest/pipeline/logs-mydata
{
  &quot;description&quot;: &quot;Routing for mydata&quot;,
  &quot;processors&quot;: [
    {
      &quot;reroute&quot;: {
        &quot;tag&quot;: &quot;foo&quot;,
        &quot;if&quot; : &quot;ctx.container?.name == 'foo'&quot;,
        &quot;dataset&quot;: &quot;foo&quot;
      }
    }
  ]
}
</code></pre>
<p>Let's test this with a document:</p>
<pre><code class="language-bash">POST logs-mydata-default/_doc
{
  &quot;@timestamp&quot;: &quot;2023-05-25T12:26:23+00:00&quot;,
  &quot;container&quot;: {
    &quot;name&quot;: &quot;foo&quot;
  }
}
</code></pre>
<p>While it would be possible to specify a routing rule for each container name, you can also route by the value of a field in the document:</p>
<pre><code class="language-bash">PUT _ingest/pipeline/logs-mydata
{
  &quot;description&quot;: &quot;Routing for mydata&quot;,
  &quot;processors&quot;: [
    {
      &quot;reroute&quot;: {
        &quot;tag&quot;: &quot;mydata&quot;,
        &quot;dataset&quot;: [
          &quot;{{container.name}}&quot;,
          &quot;mydata&quot;
        ]
      }
    }
  ]
}
</code></pre>
<p>In this example, we are using a field reference as a routing rule. If the container.name field exists in the document, it will be routed — otherwise it falls back to mydata. This can be tested with:</p>
<pre><code class="language-bash">POST logs-mydata-default/_doc
{
  &quot;@timestamp&quot;: &quot;2023-05-25T12:26:23+00:00&quot;,
  &quot;container&quot;: {
    &quot;name&quot;: &quot;foo1&quot;
  }
}

POST logs-mydata-default/_doc
{
  &quot;@timestamp&quot;: &quot;2023-05-25T12:26:23+00:00&quot;,
  &quot;container&quot;: {
    &quot;name&quot;: &quot;foo2&quot;
  }
}
</code></pre>
<p>This creates the data streams logs-foo1-default and logs-foo2-default.</p>
<p><em>NOTE: There is currently a limitation in the processor that requires the fields specified in a <code>{{field.reference}}</code> to be in a nested object notation. A dotted field name does not currently work. Also, you’ll get errors when the document contains dotted field names for any</em> <em>data_stream.*</em> <em>field. This limitation will be</em> <a href="https://github.com/elastic/elasticsearch/pull/96243"><em>fixed</em></a> <em>in 8.8.2 and 8.9.0.</em></p>
<h2>API keys</h2>
<p>When using the reroute processor, it is important that the API keys specified have permissions for the source and target indices. For example, if a pattern is used for routing from logs-mydata-default, the API key must have write permissions for <code>logs-*-*</code> as data could end up in any of these indices (see example further down).</p>
<p>We’re currently <a href="https://github.com/elastic/integrations/issues/5989">working</a> <a href="https://github.com/elastic/integrations/issues/6255">on</a> extending the API key permissions for our <a href="https://www.elastic.co/integrations/data-integrations">integrations</a> so that they allow for routing by default if you’re running a Fleet-managed Elastic Agent.</p>
<p>If you’re using a standalone Elastic Agent, or any other shipper, you can use this as a template to create your API key:</p>
<pre><code class="language-bash">POST /_security/api_key
{
  &quot;name&quot;: &quot;ingest_logs&quot;,
  &quot;role_descriptors&quot;: {
    &quot;ingest_logs&quot;: {
      &quot;cluster&quot;: [
        &quot;monitor&quot;
      ],
      &quot;indices&quot;: [
        {
          &quot;names&quot;: [
            &quot;logs-*-*&quot;
          ],
          &quot;privileges&quot;: [
            &quot;auto_configure&quot;,
            &quot;create_doc&quot;
          ]
        }
      ]
    }
  }
}
</code></pre>
<h2>Future plans</h2>
<p>In Elasticsearch 8.8, the reroute processor was released in technical preview. The plan is to adopt this in our data sink integrations like syslog, k8s, and others. Elastic will provide default routing rules that just work out of the box, but it will also be possible for users to add their own rules. If you are using our integrations, follow <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/ingest.html#pipelines-for-fleet-elastic-agent">this guide</a> on how to add a custom ingest pipeline.</p>
<h2>Try it out!</h2>
<p>This blog post has shown some sample use cases for document based routing. Try it out on your data by adjusting the commands for index templates and ingest pipelines to your own data, and get started with <a href="https://cloud.elastic.co/registration?fromURI=/home">Elastic Cloud</a> through a 7-day free trial. Let us know via <a href="https://ela.st/reroute-feedback">this feedback form</a> how you’re planning to use the <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/reroute-processor.html">reroute processor</a> and whether you have suggestions for improvement.</p>
]]></content:encoded>
            <category>observability-labs</category>
            <enclosure url="https://www.elastic.co/observability-labs/assets/images/simplifying-log-data-management-flexible-routing/observability-digital-transformation-1.jpg" length="0" type="image/jpg"/>
        </item>
    </channel>
</rss>