{"id":561,"date":"2026-02-04T18:07:50","date_gmt":"2026-02-04T18:07:50","guid":{"rendered":"https:\/\/blog.lottabytes.com\/?p=561"},"modified":"2026-02-04T18:09:08","modified_gmt":"2026-02-04T18:09:08","slug":"parsing-timestamps-with-fluentd-and-opensearch","status":"publish","type":"post","link":"https:\/\/blog.lottabytes.com\/index.php\/2026\/02\/04\/parsing-timestamps-with-fluentd-and-opensearch\/","title":{"rendered":"Parsing Timestamps with Fluentd and Opensearch"},"content":{"rendered":"\n<p>It&#8217;s the seemingly simple things that seem to eat into meaningful productivity, and for me, I&#8217;ve struggled on multiple times with Fluentd&#8217;s parsers related to non-standard time formats.  This post is an attempt to share what I&#8217;ve worked through in an attempt to help any others who might be faced with the same issues that I seem to encounter.  In this situation, I&#8217;m attempting to forward logs from <a href=\"https:\/\/suricata.io\/\">Suricata<\/a>&#8216;s fast.log to an <a href=\"https:\/\/docs.opensearch.org\/latest\/about\/\">Opensearch <\/a> instance.  The logs look like the below, and can be successfully parsed with the following regex.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"44\" src=\"https:\/\/blog.lottabytes.com\/wp-content\/uploads\/2026\/02\/image-3-1024x44.png\" alt=\"\" class=\"wp-image-566\" srcset=\"https:\/\/blog.lottabytes.com\/wp-content\/uploads\/2026\/02\/image-3-1024x44.png 1024w, https:\/\/blog.lottabytes.com\/wp-content\/uploads\/2026\/02\/image-3-300x13.png 300w, https:\/\/blog.lottabytes.com\/wp-content\/uploads\/2026\/02\/image-3-768x33.png 768w, https:\/\/blog.lottabytes.com\/wp-content\/uploads\/2026\/02\/image-3.png 1512w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">Suricata Fast Alert Syntax<\/figcaption><\/figure>\n\n\n\n<pre class=\"wp-block-code\"><code>^(?&lt;timestamp&gt;\\d{2}\\\/\\d{2}\\\/\\d{4}-\\d{2}:\\d{2}:\\d{2}\\.\\d{6})&#91;\\s]*\\&#91;(?&lt;second_field&gt;.*)\\]&#91;\\s]*\\&#91;(?&lt;rule_id&gt;\\d*:\\d*:\\d*)]\\s*(?&lt;rule_name&gt;.*)\\&#91;.*\\](?&lt;fifth_field&gt;.*)\\s*\\&#91;Classification:\\s(?&lt;class&gt;.*)\\]\\s*\\&#91;Priority:\\s(?&lt;priority&gt;\\d*)\\]\\s{(?&lt;protocol&gt;.*)}\\s(?&lt;source_ip&gt;&#91;\\d]*\\.&#91;\\d]*\\.&#91;\\d]*\\.&#91;\\d]*):(?&lt;source_port&gt;&#91;\\d]*)\\s-&gt;\\s(?&lt;dest_ip&gt;&#91;\\d]*\\.&#91;\\d]*\\.&#91;\\d]*\\.&#91;\\d]*):(?&lt;dest_port&gt;&#91;\\d]*)<\/code><\/pre>\n\n\n\n<p>In this use case I need the events to be ingested and formatted in a usable manner, with specific types such as IP address, integer, and time being correctly associated with each field.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"597\" height=\"719\" src=\"https:\/\/blog.lottabytes.com\/wp-content\/uploads\/2026\/02\/image-6.png\" alt=\"\" class=\"wp-image-569\" style=\"width:840px;height:auto\" srcset=\"https:\/\/blog.lottabytes.com\/wp-content\/uploads\/2026\/02\/image-6.png 597w, https:\/\/blog.lottabytes.com\/wp-content\/uploads\/2026\/02\/image-6-249x300.png 249w\" sizes=\"auto, (max-width: 597px) 100vw, 597px\" \/><figcaption class=\"wp-element-caption\">Working OpenSearch Record Example<\/figcaption><\/figure>\n\n\n\n<p>If left to it&#8217;s own devices however, the Fluentd Agent will not forward the timestamp field, not will it assign any types other than Text. This prohibits functionality that requires integer parsing, or IP address mapping. To resolve this issue, I have manually created my Index inside of Opensearch, specifying all of the fields along with their desired types. This can be done via the UI under <em>Index Management > Indexes > Create Index<\/em>, or via API call. A snippet of that JSON is shown below.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"447\" height=\"433\" src=\"https:\/\/blog.lottabytes.com\/wp-content\/uploads\/2026\/02\/image-1.png\" alt=\"\" class=\"wp-image-563\" srcset=\"https:\/\/blog.lottabytes.com\/wp-content\/uploads\/2026\/02\/image-1.png 447w, https:\/\/blog.lottabytes.com\/wp-content\/uploads\/2026\/02\/image-1-300x291.png 300w\" sizes=\"auto, (max-width: 447px) 100vw, 447px\" \/><figcaption class=\"wp-element-caption\">Snippet of OpenSearch Index Creation JSON<\/figcaption><\/figure>\n\n\n\n<p>During this effort I ran into a secondary issue where the timestamp would refuse to parse or ingest into OpenSearch.  A useful resource for troubleshooting, as well as defining your field types are the <a href=\"https:\/\/docs.opensearch.org\/latest\/mappings\/supported-field-types\/date\"><em>Supported Field Types &#8211; Date<\/em><\/a>, which outlines what formats can be defined to be accepted by the OpenSearch server.  If your timestamp is coming in as epoch milliseconds, but your server is expecting epoch seconds, this is how you correct that behavior as you see in the above screenshot.<\/p>\n\n\n\n<p>However, even after looking at length at the <a href=\"https:\/\/docs.fluentd.org\/configuration\/parse-section#time-parameters\">Fluentd Parser&#8217;s time documentation<\/a> I was still unable to ingest timestamps on events correctly.  As you can see below, I have the <em>time_format<\/em> specified&#8230;<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"535\" height=\"349\" src=\"https:\/\/blog.lottabytes.com\/wp-content\/uploads\/2026\/02\/image-5.png\" alt=\"\" class=\"wp-image-568\" srcset=\"https:\/\/blog.lottabytes.com\/wp-content\/uploads\/2026\/02\/image-5.png 535w, https:\/\/blog.lottabytes.com\/wp-content\/uploads\/2026\/02\/image-5-300x196.png 300w\" sizes=\"auto, (max-width: 535px) 100vw, 535px\" \/><figcaption class=\"wp-element-caption\">Fluentd Configuration that Doesn&#8217;t Work<\/figcaption><\/figure>\n\n\n\n<p>&#8230;and if you use the underlying <a href=\"https:\/\/docs.ruby-lang.org\/en\/2.4.0\/Time.html#method-c-strptime\">Ruby strptime function<\/a> in a <a href=\"https:\/\/onecompiler.com\/ruby\/\">test environment<\/a> it works correctly against the timestamp and the date format.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"683\" height=\"205\" src=\"https:\/\/blog.lottabytes.com\/wp-content\/uploads\/2026\/02\/image-2.png\" alt=\"\" class=\"wp-image-564\" srcset=\"https:\/\/blog.lottabytes.com\/wp-content\/uploads\/2026\/02\/image-2.png 683w, https:\/\/blog.lottabytes.com\/wp-content\/uploads\/2026\/02\/image-2-300x90.png 300w\" sizes=\"auto, (max-width: 683px) 100vw, 683px\" \/><figcaption class=\"wp-element-caption\">Ruby Sandbox Shows Code Working in Theory<\/figcaption><\/figure>\n\n\n\n<p>Yet, a variety of issues arise, from errors like the below (with the above config), all resulting in either an incorrect time being associated, or no time at all.  I have even attempted to build out a custom date regex on the OpenSearch Index matching what I understand the Fluentd agent to be sending.  All to no avail&#8230;<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"57\" src=\"https:\/\/blog.lottabytes.com\/wp-content\/uploads\/2026\/02\/image-4-1024x57.png\" alt=\"\" class=\"wp-image-567\" srcset=\"https:\/\/blog.lottabytes.com\/wp-content\/uploads\/2026\/02\/image-4-1024x57.png 1024w, https:\/\/blog.lottabytes.com\/wp-content\/uploads\/2026\/02\/image-4-300x17.png 300w, https:\/\/blog.lottabytes.com\/wp-content\/uploads\/2026\/02\/image-4-768x43.png 768w, https:\/\/blog.lottabytes.com\/wp-content\/uploads\/2026\/02\/image-4-1536x86.png 1536w, https:\/\/blog.lottabytes.com\/wp-content\/uploads\/2026\/02\/image-4.png 1878w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">Fluentd Ingestion Error Message<\/figcaption><\/figure>\n\n\n\n<p>At the end of this endeavor I discovered that a combination of things allowed for the proper ingestion of timestamps by a conversion of the timestamp value to epoch seconds.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Manual creation of the index, specifying the <em>epoch_seconds<\/em> as the date format.<\/li>\n\n\n\n<li>Using the <em><a href=\"https:\/\/docs.fluentd.org\/configuration\/parse-section#types-parameter\">Types Parameter<\/a><\/em> in Fluentd to convert my timestamp field to a time (in Fluentd&#8217;s eyes), using the specified date format.  You can see this below in Line 17.  Simply specifying the same date format using the <em>time_format<\/em> key does not work.<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"419\" src=\"https:\/\/blog.lottabytes.com\/wp-content\/uploads\/2026\/02\/image-1024x419.png\" alt=\"\" class=\"wp-image-562\" srcset=\"https:\/\/blog.lottabytes.com\/wp-content\/uploads\/2026\/02\/image-1024x419.png 1024w, https:\/\/blog.lottabytes.com\/wp-content\/uploads\/2026\/02\/image-300x123.png 300w, https:\/\/blog.lottabytes.com\/wp-content\/uploads\/2026\/02\/image-768x315.png 768w, https:\/\/blog.lottabytes.com\/wp-content\/uploads\/2026\/02\/image.png 1067w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">Working Fluentd Configuration<\/figcaption><\/figure>\n\n\n\n<p>This experiment has taken far longer than anticipated, but I was able to learn more about Opensearch and Fluentd along the way.  I hope that this helps accelerate someone else on their journey, and if not, I&#8217;ll probably end up reading my own notes here in the future when I run into similar problems again.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>It&#8217;s the seemingly simple things that seem to eat into meaningful productivity, and for me, I&#8217;ve struggled on multiple times with Fluentd&#8217;s parsers related to non-standard time formats. This post is an attempt to share what I&#8217;ve worked through in an attempt to help any others who might be faced with the same issues that &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/blog.lottabytes.com\/index.php\/2026\/02\/04\/parsing-timestamps-with-fluentd-and-opensearch\/\" class=\"more-link\">Read more<span class=\"screen-reader-text\"> &#8220;Parsing Timestamps with Fluentd and Opensearch&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[174,175,169,84,170,82,167,166,172,173,56,168,171],"class_list":["post-561","post","type-post","status-publish","format-standard","hentry","category-uncategorized","tag-epoch","tag-epoch_second","tag-expression","tag-fluentd","tag-keep_time_key","tag-logging","tag-logs","tag-opensearch","tag-ruby","tag-strptime","tag-suricata","tag-time_key","tag-types"],"_links":{"self":[{"href":"https:\/\/blog.lottabytes.com\/index.php\/wp-json\/wp\/v2\/posts\/561","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.lottabytes.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.lottabytes.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.lottabytes.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.lottabytes.com\/index.php\/wp-json\/wp\/v2\/comments?post=561"}],"version-history":[{"count":5,"href":"https:\/\/blog.lottabytes.com\/index.php\/wp-json\/wp\/v2\/posts\/561\/revisions"}],"predecessor-version":[{"id":573,"href":"https:\/\/blog.lottabytes.com\/index.php\/wp-json\/wp\/v2\/posts\/561\/revisions\/573"}],"wp:attachment":[{"href":"https:\/\/blog.lottabytes.com\/index.php\/wp-json\/wp\/v2\/media?parent=561"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.lottabytes.com\/index.php\/wp-json\/wp\/v2\/categories?post=561"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.lottabytes.com\/index.php\/wp-json\/wp\/v2\/tags?post=561"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}