Skip to content

feat: logstash ingestion - #3940

Open
FranekKubis wants to merge 7 commits into
Logflare:mainfrom
FranekKubis:fk/o11y-2422/logstash-ingestion
Open

FranekKubis wants to merge 7 commits into
Logflare:mainfrom
FranekKubis:fk/o11y-2422/logstash-ingestion

Conversation

@FranekKubis

@FranekKubis FranekKubis commented Sep 7, 2026

Copy link
Copy Markdown

Closes: O11Y-2422

Add logstash transport to elastic backend

Adds a third transport value to the :elastic backend, delivering events to a
Logstash http input as ECS-flavoured JSON. timestamp and event_message are
lifted to @timestamp and message so a receiving pipeline needs no date
filter; remaining fields stay top-level and Logflare metadata is namespaced
under logflare. Reuses WebhookAdaptor (HTTP/1.1, optional basic auth, gzip)
via the existing format_batch hook.

Also fixes three pre-existing issues surfaced while verifying end to end:

  • ElasticAdaptor.validate_config/1 had no catch-all clause, so an unsupported
    transport raised CaseClauseError instead of returning an invalid changeset.
    The existing "rejects unknown transport" test was already failing on this.

  • Logflare.FinchDefaultHttp1 was never started in single-tenant Postgres mode,
    so every WebhookAdaptor-based backend (elastic, loki, webhook) crashed with
    "unknown registry" on delivery.

  • The source edit page hardcoded which backend types it would render, hiding
    elastic, loki, clickhouse, s3, axiom, otlp, incidentio and last9 and making
    them impossible to attach to a source. Backend types and labels now derive
    from a single registry in Logflare.Backends.Backend, with a compile-time
    check that every adaptor has a label. Side effect: the "New backend" dropdown
    is now ordered alphabetically.

Adds a logstash docker-compose service and test/logstash.conf for local
verification. Note that outbound requests are SSRF-protected, so a local
Logstash must be reached through a tunnel rather than localhost.

@FranekKubis FranekKubis changed the title WIP: O11Y-2422: logstash ingestion wip: logstash ingestion Sep 7, 2026
@FranekKubis FranekKubis changed the title wip: logstash ingestion feat: logstash ingestion Sep 9, 2026
@FranekKubis
FranekKubis marked this pull request as ready for review September 9, 2026 12:30
@FranekKubis
FranekKubis force-pushed the fk/o11y-2422/logstash-ingestion branch from b354054 to fe7b7d4 Compare September 9, 2026 12:58
@Ziinc
Ziinc requested a review from Baishan September 9, 2026 16:34
%{
url: config.url,
http: "http1",
gzip: Map.get(config, :gzip, true),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should always set this to true and remove it as a configurable.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can remove it from the otlp drain as well, don't see a point in letting users configure it

password: :string,
# logstash, otlp
gzip: :boolean,
headers: {:map, :string},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can extend filebeat to handle the headers as well do that this is a common config across all 3

headers: {:map, :string},
# otlp
endpoint: :string,
protocol: :string

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Protocol can be removed as a config since only one is supported.

gzip: :boolean,
headers: {:map, :string},
# otlp
endpoint: :string,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm wonder if it's worth converting this to use :url so that it's consistent across all 3...thoughts?

@FranekKubis FranekKubis Sep 14, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rather keep it as is because endpoint it is OTLP's own vocabulary (e.g. OTEL_EXPORTER_OTLP_ENDPOINT / OTEL_EXPORTER_OTLP_LOGS_ENDPOINT) and it is not quite a synonym for url.


@impl Logflare.Backends.Adaptor
def test_connection(_), do: {:error, :not_implemented}
defp redact_header(k, v) do

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There some common header redaction logic across the backends, should move them to a utility function under the HttpBased module

Comment thread mix.lock Outdated
"retry": {:hex, :retry, "0.19.0", "aeb326d87f62295d950f41e1255fe6f43280a1b390d36e280b7c9b00601ccbc2", [:mix], [], "hexpm", "85ef376aa60007e7bff565c366310966ec1bd38078765a0e7f20ec8a220d02ca"},
"rustler": {:hex, :rustler, "0.37.3", "5f4e6634d43b26f0a69834dd1d3ed4e1710b022a053bf4a670220c9540c92602", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "a6872c6f53dcf00486d1e7f9e046e20e01bf1654bdacc4193016c2e8002b32a2"},
"rustler_precompiled": {:hex, :rustler_precompiled, "0.8.2", "5f25cbe220a8fac3e7ad62e6f950fcdca5a5a5f8501835d2823e8c74bf4268d5", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:rustler, "~> 0.23", [hex: :rustler, repo: "hexpm", optional: true]}], "hexpm", "63d1bd5f8e23096d1ff851839923162096364bac8656a4a3c00d1fff8e83ee0a"},
"rustler_precompiled": {:hex, :rustler_precompiled, "0.9.0", "3a052eda09f3d2436364645cc1f13279cf95db310eb0c17b0d8f25484b233aa0", [:mix], [{:rustler, "~> 0.23", [hex: :rustler, repo: "hexpm", optional: true]}], "hexpm", "471d97315bd3bf7b64623418b3693eedd8e47de3d1cb79a0ac8f9da7d770d94c"},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No deps changes, should remove this from diff

)

start_supervised!({AdaptorSupervisor, {source, backend}})
:timer.sleep(500)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should avoid timer usage

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should wrap an assertion with TestUtils retry_assert if there's a race condition and we need to wait for proc to startup


assert html =~ "Logstash URL"
refute html =~ "Filebeat URL"
refute html =~ "Elastic Supabase Endpoint"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The otlp endpoint is bundled with elasticsearch actually, not supabase specific.

Suggested change
refute html =~ "Elastic Supabase Endpoint"
refute html =~ "Elasticsearch OTLP Endpoint"

@Ziinc

Ziinc commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

Could you also add a demo video of the setup + ingestion? 🙏

@FranekKubis

Copy link
Copy Markdown
Author

I am adding a rough recording of clicking my way through the app, initializing new backend for logstash and sending logs to the logflare source connected to the logstash backend.
Video posted on linear:
https://linear.app/supabase/issue/O11Y-2422/implement-logstash-ingestion-for-the-elk-stack#comment-b2d875f2

@FranekKubis
FranekKubis force-pushed the fk/o11y-2422/logstash-ingestion branch from 00d9e43 to 48e4307 Compare September 15, 2026 09:15
Comment thread lib/logflare_web/live/backends/components/backend_form.heex Outdated
Comment thread lib/logflare/backends/adaptor/elastic_adaptor.ex
@FranekKubis
FranekKubis force-pushed the fk/o11y-2422/logstash-ingestion branch from 62f6107 to b800ab0 Compare September 17, 2026 11:28
@FranekKubis
FranekKubis requested a review from Ziinc September 17, 2026 11:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants