fix(ingestion): restore Kinesis Firehose and GCP Pub/Sub tabs under Custom > Logs (#14916)

This commit is contained in:
Prabhat Sharma
2026-09-29 22:10:28 +08:00
committed by GitHub
parent 434bb759da
commit 4eb6919e02
26 changed files with 283 additions and 2 deletions
@@ -9517,6 +9517,7 @@
"fluentbit": "b6344fe6e6115ccf",
"fluentd": "4f2c848b37c5a944",
"gactions": "fae83bd48c808f08",
"gcpLogs": "c54590f981ee31f1",
"generateRUMTokenLabel": "475c7f1c1a5cff60",
"generateRUMTokenMessage": "ea76eb1e37cb811f",
"header": "a22bd608ff67405e",
@@ -9649,6 +9650,7 @@
}
},
"jenkins": "9a4d10e69361c7d6",
"kinesisFirehose": "d1e2ebf59ff37b7d",
"languagesLabel": "73d87075dd9f09ac",
"launchCloudFormationStack": "2e4bfaf27c788b70",
"linuxUnixMacosManualInstall": "4cce8d7c825eec13",
@@ -129,7 +129,9 @@ describe("IngestLogs Component", () => {
"curl",
"fluentbit",
"fluentd",
"kinesisfirehose",
"vector",
"gcpLogs",
"syslogNg",
"splunkHec",
"loongcollector",
@@ -243,6 +245,30 @@ describe("IngestLogs Component", () => {
tw.unmount();
});
it("should push with org_identifier query when route is 'kinesisfirehose'", () => {
mockRouter.currentRoute.value.name = "kinesisfirehose";
const tw = mount(IngestLogs, buildMountOptions());
expect(mockRouter.push).toHaveBeenCalledWith({
name: "kinesisfirehose",
query: {
org_identifier: store.state.selectedOrganization.identifier,
},
});
tw.unmount();
});
it("should push with org_identifier query when route is 'gcpLogs'", () => {
mockRouter.currentRoute.value.name = "gcpLogs";
const tw = mount(IngestLogs, buildMountOptions());
expect(mockRouter.push).toHaveBeenCalledWith({
name: "gcpLogs",
query: {
org_identifier: store.state.selectedOrganization.identifier,
},
});
tw.unmount();
});
it("should push with org_identifier query when route is 'syslogNg'", () => {
mockRouter.currentRoute.value.name = "syslogNg";
const tw = mount(IngestLogs, buildMountOptions());
@@ -77,6 +77,30 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
:icon="'img:' + getImageURL('images/ingestion/vector.png')"
:label="t('ingestion.vector')"
/>
<ORouteTab
name="kinesisfirehose"
data-test="ingestion-logs-tab-kinesisfirehose"
:to="{
name: 'kinesisfirehose',
query: {
org_identifier: store.state.selectedOrganization.identifier,
},
}"
:icon="'img:' + getImageURL('images/ingestion/kinesis_firehose.svg')"
:label="t('ingestion.kinesisFirehose')"
/>
<ORouteTab
name="gcpLogs"
data-test="ingestion-logs-tab-gcplogs"
:to="{
name: 'gcpLogs',
query: {
org_identifier: store.state.selectedOrganization.identifier,
},
}"
:icon="'img:' + getImageURL('images/ingestion/gcp.svg')"
:label="t('ingestion.gcpLogs')"
/>
<ORouteTab
name="ingestLogsFromOtel"
:to="{
@@ -187,7 +211,9 @@ export default defineComponent({
"curl",
"fluentbit",
"fluentd",
"kinesisfirehose",
"vector",
"gcpLogs",
"syslogNg",
"splunkHec",
"loongcollector",
@@ -0,0 +1,76 @@
// Copyright 2026 OpenObserve Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import { describe, it, expect, vi, beforeEach } from "vitest";
import { mount } from "@vue/test-utils";
import { createStore } from "vuex";
import KinesisFirehose from "./KinesisFirehose.vue";
vi.mock("@/utils/zincutils", () => ({
getEndPoint: vi.fn(() => ({
url: "https://test.example.com:5080",
host: "test.example.com",
port: "5080",
protocol: "https",
tls: true,
})),
getIngestionURL: vi.fn(() => "https://test.example.com:5080"),
}));
vi.mock("@/components/CopyContent.vue", () => ({
default: {
name: "CopyContent",
props: ["content"],
template: "<div class='copy-content'>{{ content }}</div>",
},
}));
describe("KinesisFirehose.vue", () => {
let wrapper: any;
beforeEach(() => {
const store = createStore({
state: {
selectedOrganization: {
identifier: "test-org",
},
},
});
wrapper = mount(KinesisFirehose, {
global: {
plugins: [store],
},
props: {
currOrgIdentifier: "test-org",
currUserEmail: "test@example.com",
},
});
});
it("has the expected component name", () => {
expect(wrapper.vm.$options.name).toBe("KinesisFirehose");
});
it("shows the org's Kinesis Firehose HTTP endpoint", () => {
expect(wrapper.find(".copy-content").text()).toContain(
"HTTP Endpoint: https://test.example.com:5080/aws/test-org/default/_kinesis_firehose",
);
});
it("uses the basic passcode placeholder as the access key", () => {
expect(wrapper.vm.content).toContain("Access Key: [BASIC_PASSCODE]");
});
});
@@ -0,0 +1,53 @@
<!-- Copyright 2026 OpenObserve Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<template>
<IngestionContent>
<CopyContent class="copy-content-container-cls" :content="raw(content)" />
</IngestionContent>
</template>
<script lang="ts">
import { raw } from "@/types/i18n";
import { defineComponent } from "vue";
import { useStore } from "vuex";
import { getEndPoint, getIngestionURL } from "@/utils/zincutils";
import CopyContent from "@/components/CopyContent.vue";
import IngestionContent from "@/components/ingestion/IngestionContent.vue";
export default defineComponent({
name: "KinesisFirehose",
props: {
currOrgIdentifier: {
type: String,
},
currUserEmail: {
type: String,
},
},
components: { CopyContent, IngestionContent },
setup() {
const store = useStore();
const endpoint = getEndPoint(getIngestionURL());
const content = `HTTP Endpoint: ${endpoint.url}/aws/${store.state.selectedOrganization.identifier}/default/_kinesis_firehose
Access Key: [BASIC_PASSCODE]`;
return {
raw,
content,
};
},
});
</script>
@@ -110,7 +110,9 @@ describe("IngestLogs Index Component", () => {
"curl",
"fluentbit",
"fluentd",
"kinesisfirehose",
"vector",
"gcpLogs",
"syslogNg",
"splunkHec",
"loongcollector",
@@ -306,7 +308,9 @@ describe("IngestLogs Index Component", () => {
"curl",
"fluentbit",
"fluentd",
"kinesisfirehose",
"vector",
"gcpLogs",
"syslogNg",
"splunkHec",
"loongcollector",
@@ -33,6 +33,7 @@ vi.mock("@/components/ingestion/logs/FluentBit.vue", () => ({ default: {} }));
vi.mock("@/components/ingestion/logs/Fluentd.vue", () => ({ default: {} }));
vi.mock("@/components/ingestion/logs/Vector.vue", () => ({ default: {} }));
vi.mock("@/components/ingestion/logs/Curl.vue", () => ({ default: {} }));
vi.mock("@/components/ingestion/logs/KinesisFirehose.vue", () => ({ default: {} }));
vi.mock("@/components/ingestion/recommended/AWSConfig.vue", () => ({ default: {} }));
vi.mock("@/components/ingestion/recommended/GCPConfig.vue", () => ({ default: {} }));
vi.mock("@/components/ingestion/recommended/AzureConfig.vue", () => ({ default: {} }));
@@ -206,6 +207,8 @@ describe("useIngestionRoutes", () => {
expect(logRouteNames).toContain("logstash");
expect(logRouteNames).toContain("syslogNg");
expect(logRouteNames).toContain("loongcollector");
expect(logRouteNames).toContain("kinesisfirehose");
expect(logRouteNames).toContain("gcpLogs");
});
it("should have metrics routes under custom", () => {
@@ -965,6 +968,38 @@ describe("useIngestionRoutes", () => {
expect(typeof fluentbitRoute.beforeEnter).toBe("function");
});
it("should have kinesisfirehose route with correct configuration", () => {
const routes = useIngestionRoutes();
const customRoute = routes[0].children.find((child: any) => child.name === "custom");
const logsRoute = customRoute.children.find((child: any) => child.name === "ingestLogs");
const firehoseRoute = logsRoute.children.find(
(child: any) => child.name === "kinesisfirehose",
);
expect(firehoseRoute).toBeDefined();
expect(firehoseRoute.path).toBe("kinesisfirehose");
expect(firehoseRoute.component).toBeDefined();
expect(typeof firehoseRoute.beforeEnter).toBe("function");
});
it("should have gcpLogs route reusing the recommended GCP page", () => {
const routes = useIngestionRoutes();
const customRoute = routes[0].children.find((child: any) => child.name === "custom");
const logsRoute = customRoute.children.find((child: any) => child.name === "ingestLogs");
const gcpLogsRoute = logsRoute.children.find((child: any) => child.name === "gcpLogs");
const recommendedRoute = routes[0].children.find(
(child: any) => child.name === "recommended",
);
const gcpConfigRoute = recommendedRoute.children.find(
(child: any) => child.name === "GCPConfig",
);
expect(gcpLogsRoute).toBeDefined();
expect(gcpLogsRoute.path).toBe("gcp");
expect(gcpLogsRoute.component).toBe(gcpConfigRoute.component);
expect(typeof gcpLogsRoute.beforeEnter).toBe("function");
});
it("should have prometheus route with correct configuration", () => {
const routes = useIngestionRoutes();
const customRoute = routes[0].children.find((child: any) => child.name === "custom");
@@ -23,6 +23,7 @@ import FluentBit from "@/components/ingestion/logs/FluentBit.vue";
import Fluentd from "@/components/ingestion/logs/Fluentd.vue";
import Vector from "@/components/ingestion/logs/Vector.vue";
import Curl from "@/components/ingestion/logs/Curl.vue";
import KinesisFirehose from "@/components/ingestion/logs/KinesisFirehose.vue";
import AWSConfig from "@/components/ingestion/recommended/AWSConfig.vue";
import GCPConfig from "@/components/ingestion/recommended/GCPConfig.vue";
import AzureConfig from "@/components/ingestion/recommended/AzureConfig.vue";
@@ -199,6 +200,22 @@ const useIngestionRoutes = () => {
routeGuard(to, from, next);
},
},
{
path: "kinesisfirehose",
name: "kinesisfirehose",
component: KinesisFirehose,
beforeEnter(to: any, from: any, next: any) {
routeGuard(to, from, next);
},
},
{
path: "gcp",
name: "gcpLogs",
component: GCPConfig,
beforeEnter(to: any, from: any, next: any) {
routeGuard(to, from, next);
},
},
{
path: "filebeat",
name: "filebeat",
+2
View File
@@ -3748,6 +3748,8 @@
"logstash": "Logstash",
"syslogNg": "Syslog-ng",
"loongCollector": "LoongCollector",
"kinesisFirehose": "Kinesis Firehose",
"gcpLogs": "سجلات GCP عبر (Pub/Sub)",
"metrics": {
"prometheus": "Prometheus",
"vmagent": "vmagent",
+2
View File
@@ -3748,6 +3748,8 @@
"logstash": "Logstash",
"syslogNg": "Syslog-ng",
"loongCollector": "LoongCollector",
"kinesisFirehose": "Kinesis Firehose",
"gcpLogs": "GCP Logs über (Pub/Sub)",
"metrics": {
"prometheus": "Prometheus",
"vmagent": "vmagent",
+2
View File
@@ -3748,6 +3748,8 @@
"logstash": "Logstash",
"syslogNg": "Syslog-ng",
"loongCollector": "LoongCollector",
"kinesisFirehose": "Kinesis Firehose",
"gcpLogs": "GCP Logs via (Pub/Sub)",
"metrics": {
"prometheus": "Prometheus",
"vmagent": "vmagent",
+2
View File
@@ -3748,6 +3748,8 @@
"logstash": "Logstash",
"syslogNg": "Syslog-ng",
"loongCollector": "LoongCollector",
"kinesisFirehose": "Kinesis Firehose",
"gcpLogs": "Logs de GCP vía (Pub/Sub)",
"metrics": {
"prometheus": "Prometheus",
"vmagent": "vmagent",
+2
View File
@@ -3748,6 +3748,8 @@
"logstash": "Logstash",
"syslogNg": "Syslog-ng",
"loongCollector": "LoongCollector",
"kinesisFirehose": "Kinesis Firehose",
"gcpLogs": "Logs GCP via (Pub/Sub)",
"metrics": {
"prometheus": "Prometheus",
"vmagent": "vmagent",
+2
View File
@@ -3748,6 +3748,8 @@
"logstash": "Logstash",
"syslogNg": "Syslog-ng",
"loongCollector": "LoongCollector",
"kinesisFirehose": "Kinesis Firehose",
"gcpLogs": "Log GCP tramite (Pub/Sub)",
"metrics": {
"prometheus": "Prometheus",
"vmagent": "vmagent",
+2
View File
@@ -3748,6 +3748,8 @@
"logstash": "Logstash",
"syslogNg": "Syslog-ng",
"loongCollector": "LoongCollector",
"kinesisFirehose": "Kinesis Firehose",
"gcpLogs": "GCP ログ (Pub/Sub 経由)",
"metrics": {
"prometheus": "Prometheus",
"vmagent": "vmagent",
+2
View File
@@ -3748,6 +3748,8 @@
"logstash": "Logstash",
"syslogNg": "Syslog-ng",
"loongCollector": "LoongCollector",
"kinesisFirehose": "Kinesis Firehose",
"gcpLogs": "Pub/Sub을 통한 GCP 로그",
"metrics": {
"prometheus": "Prometheus",
"vmagent": "vmagent",
+2
View File
@@ -3748,6 +3748,8 @@
"logstash": "Logstash",
"syslogNg": "Syslog-ng",
"loongCollector": "LoongCollector",
"kinesisFirehose": "Kinesis Firehose",
"gcpLogs": "GCP Logboeken via (Pub/Sub)",
"metrics": {
"prometheus": "Prometheus",
"vmagent": "vmagent",
+2
View File
@@ -3748,6 +3748,8 @@
"logstash": "Logstash",
"syslogNg": "Syslog-ng",
"loongCollector": "LoongCollector",
"kinesisFirehose": "Kinesis Firehose",
"gcpLogs": "Logi GCP przez (Pub/Sub)",
"metrics": {
"prometheus": "Prometheus",
"vmagent": "vmagent",
+2
View File
@@ -3748,6 +3748,8 @@
"logstash": "Logstash",
"syslogNg": "Syslog-ng",
"loongCollector": "LoongCollector",
"kinesisFirehose": "Kinesis Firehose",
"gcpLogs": "Registros do GCP via (Pub/Sub)",
"metrics": {
"prometheus": "Prometheus",
"vmagent": "vmagent",
+2
View File
@@ -3748,6 +3748,8 @@
"logstash": "Logstash",
"syslogNg": "Syslog-ng",
"loongCollector": "LoongCollector",
"kinesisFirehose": "Kinesis Firehose",
"gcpLogs": "Логи GCP через (Pub/Sub)",
"metrics": {
"prometheus": "Prometheus",
"vmagent": "vmagent",
+2
View File
@@ -3748,6 +3748,8 @@
"logstash": "Logstash",
"syslogNg": "Syslog-ng",
"loongCollector": "LoongCollector",
"kinesisFirehose": "Kinesis Firehose",
"gcpLogs": "Pub/Sub üzerinden GCP Günlükleri",
"metrics": {
"prometheus": "Prometheus",
"vmagent": "vmagent",
+2
View File
@@ -3748,6 +3748,8 @@
"logstash": "Logstash",
"syslogNg": "Syslog-ng",
"loongCollector": "LoongCollector",
"kinesisFirehose": "Kinesis Firehose",
"gcpLogs": "Nhật ký GCP qua (Pub/Sub)",
"metrics": {
"prometheus": "Prometheus",
"vmagent": "vmagent",
+2
View File
@@ -3748,6 +3748,8 @@
"logstash": "Logstash",
"syslogNg": "Syslog-ng",
"loongCollector": "LoongCollector",
"kinesisFirehose": "Kinesis Firehose",
"gcpLogs": "GCP 日志(通过 Pub/Sub)",
"metrics": {
"prometheus": "Prometheus",
"vmagent": "vmagent",
+2
View File
@@ -3748,6 +3748,8 @@
"logstash": "Logstash",
"syslogNg": "Syslog-ng",
"loongCollector": "LoongCollector",
"kinesisFirehose": "Kinesis Firehose",
"gcpLogs": "透過 (Pub/Sub) 的 GCP 日誌",
"metrics": {
"prometheus": "Prometheus",
"vmagent": "vmagent",
+10 -2
View File
@@ -267,6 +267,14 @@ describe("resolveTab", () => {
expect(resolveTab("ingestLogs", "vector", "curl")).toBe("vector");
});
it("ingestLogs – kinesisfirehose", () => {
expect(resolveTab("ingestLogs", "kinesisfirehose", "curl")).toBe("kinesisfirehose");
});
it("ingestLogs – gcpLogs", () => {
expect(resolveTab("ingestLogs", "gcpLogs", "curl")).toBe("gcpLogs");
});
it("ingestLogs – ingestLogsFromOtel", () => {
expect(resolveTab("ingestLogs", "ingestLogsFromOtel", "curl")).toBe("ingestLogsFromOtel");
});
@@ -469,8 +477,8 @@ describe("ROUTE_TAB_MAPS", () => {
expect(Object.keys(ROUTE_TAB_MAPS.ingestMetrics)).toHaveLength(7);
});
it("ingestLogs has 10 entries", () => {
expect(Object.keys(ROUTE_TAB_MAPS.ingestLogs)).toHaveLength(10);
it("ingestLogs has 12 entries", () => {
expect(Object.keys(ROUTE_TAB_MAPS.ingestLogs)).toHaveLength(12);
});
it("billings has 4 entries", () => {
+2
View File
@@ -119,6 +119,8 @@ const ROUTE_TAB_MAPS: Record<string, Record<string, string>> = {
fluentbit: "fluentbit",
fluentd: "fluentd",
vector: "vector",
kinesisfirehose: "kinesisfirehose",
gcpLogs: "gcpLogs",
ingestLogsFromOtel: "ingestLogsFromOtel",
logstash: "logstash",
syslogNg: "syslogNg",