Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions hermes-console/json-server/db.json
Original file line number Diff line number Diff line change
Expand Up @@ -753,6 +753,12 @@
"topicDetailsUrl": "",
"subscriptionIframeUrl": "",
"subscriptionDetailsUrl": ""
},
"logs": {
"enabled": true,
"baseUrl": "https://logging.example.com/app/discover",
"topicLogsFilter": "#/?_a=(filters:!((query:(match_phrase:(topic-name:'{{topic_name}}')))))",
"subscriptionLogsFilter": "#/?_a=(filters:!((query:(match_phrase:(subscription-name:'{{subscription_name}}')))))"
}
},
"stats": {
Expand Down
8 changes: 8 additions & 0 deletions hermes-console/src/api/app-configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export interface AppConfiguration {
consistency: ConsistencyViewConfiguration;
group: GroupViewConfiguration;
costs: CostsConfiguration;
logs: LogsConfiguration;
}

export interface ConsoleConfiguration {
Expand Down Expand Up @@ -176,3 +177,10 @@ export interface OfflineRetransmission {
globalTaskQueueUrl: string;
monitoringDocsUrl: string;
}

export interface LogsConfiguration {
enabled: boolean;
baseUrl: string;
topicLogsFilter: string;
subscriptionLogsFilter: string;
}
8 changes: 8 additions & 0 deletions hermes-console/src/dummy/app-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,4 +137,12 @@ export const dummyAppConfig: AppConfiguration = {
subscriptionIframeUrl: '',
subscriptionDetailsUrl: '',
},
logs: {
enabled: true,
baseUrl: 'https://logging.example.com/app/discover',
topicLogsFilter:
"#/?_a=(filters:!((query:(match_phrase:(topic-name:'{{topic_name}}')))))",
subscriptionLogsFilter:
"#/?_a=(filters:!((query:(match_phrase:(subscription-name:'{{subscription_name}}')))))",
},
};
8 changes: 8 additions & 0 deletions hermes-console/src/i18n/en-US/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,7 @@ const en_US = {
offlineClients: 'Offline clients',
messages: 'Messages',
offlineRetransmission: 'Offline retransmission',
logs: 'Logs',
},
confirmationDialog: {
remove: {
Expand Down Expand Up @@ -443,6 +444,7 @@ const en_US = {
messages: 'Messages',
filters: 'Filters',
mutations: 'Mutations',
logs: 'Logs',
},
confirmationDialog: {
remove: {
Expand Down Expand Up @@ -911,6 +913,12 @@ const en_US = {
title: 'Costs',
detailsButton: 'Dashboard',
},
logsCard: {
title: 'Logs',
viewLogs: 'View logs',
description:
'View Hermes logs for this resource in an external logging provider.',
},
trackingCard: {
title: 'Tracking',
noTrackingUrls: 'No tracking urls available',
Expand Down
46 changes: 46 additions & 0 deletions hermes-console/src/views/subscription/SubscriptionView.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ describe('SubscriptionView', () => {
'subscription.tabs.general',
'subscription.tabs.filters',
'subscription.tabs.messages',
'subscription.tabs.logs',
];
expectedTabs.forEach((boxTitle) => {
expect(getByText(boxTitle)).toBeVisible();
Expand All @@ -111,6 +112,7 @@ describe('SubscriptionView', () => {
'subscription.tabs.general',
'subscription.tabs.filters',
'subscription.tabs.messages',
'subscription.tabs.logs',
])('should activate tab on click', async (tab: string) => {
// given
const user = userEvent.setup();
Expand Down Expand Up @@ -433,4 +435,48 @@ describe('SubscriptionView', () => {
// then
expect(queryByText('trackingCard.title')).not.toBeInTheDocument();
});

it('should show logs card on logs tab click', async () => {
// given
const user = userEvent.setup();
const { getByText } = render(SubscriptionView, {
testPinia: createTestingPiniaWithState(),
});

// when
await user.click(getByText('subscription.tabs.logs'));

// then
expect(getByText('logsCard.title')).toBeVisible();
expect(getByText('logsCard.viewLogs')).toBeVisible();
expect(getByText('logsCard.description')).toBeVisible();
});

it('should not show logs tab when kibana is disabled in app config', () => {
// when
const { queryByText } = render(SubscriptionView, {
testPinia: createTestingPinia({
initialState: {
appConfig: {
appConfig: {
...dummyAppConfig,
logs: {
enabled: false,
baseUrl: '',
topicLogsFilter: '',
subscriptionLogsFilter: '',
},
},
loading: false,
error: {
loadConfig: null,
},
},
},
}),
});

// then
expect(queryByText('subscription.tabs.logs')).not.toBeInTheDocument();
});
});
49 changes: 49 additions & 0 deletions hermes-console/src/views/subscription/SubscriptionView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -160,11 +160,24 @@
),
}));

const subscriptionLogsUrl = computed(() => {
const logs = configStore.appConfig?.logs;
if (!logs?.baseUrl || !logs?.subscriptionLogsFilter) return '';
return (
logs.baseUrl +
logs.subscriptionLogsFilter.replace(
'{{subscription_name}}',
subscriptionId.value,
)
);
});

const Tab = {
General: 'general',
Messages: 'messages',
Filters: 'filters',
Mutations: 'mutations',
Logs: 'logs',
};
const currentTab = ref<string>(Tab.General);
</script>
Expand Down Expand Up @@ -252,6 +265,12 @@
<v-tab :value="Tab.Messages" class="text-capitalize">{{
$t('subscription.tabs.messages')
}}</v-tab>
<v-tab
v-if="configStore.appConfig?.logs.enabled"
:value="Tab.Logs"
class="text-capitalize"
>{{ $t('subscription.tabs.logs') }}</v-tab
>
</v-tabs>
</v-container>

Expand Down Expand Up @@ -350,6 +369,36 @@
</v-row>
</v-container>
</v-tabs-window-item>

<v-tabs-window-item
v-if="configStore.appConfig?.logs.enabled"
:value="Tab.Logs"
>
<v-container class="py-0">
<v-card rounded="lg">
<v-card-item class="border-b">
<div class="d-flex justify-space-between align-start">
<v-card-title class="font-weight-bold">
{{ $t('logsCard.title') }}
</v-card-title>
<v-btn
class="text-none"
prepend-icon="mdi-open-in-new"
target="_blank"
:href="subscriptionLogsUrl"
variant="text"
color="primary"
>
{{ $t('logsCard.viewLogs') }}
</v-btn>
</div>
</v-card-item>
<v-card-text>
{{ $t('logsCard.description') }}
</v-card-text>
</v-card>
</v-container>
</v-tabs-window-item>
</v-tabs-window>
</template>
</v-container>
Expand Down
46 changes: 46 additions & 0 deletions hermes-console/src/views/topic/TopicView.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ describe('TopicView', () => {
'topicView.tabs.offlineClients',
'topicView.tabs.messages',
'topicView.tabs.offlineRetransmission',
'topicView.tabs.logs',
];

// when
Expand All @@ -132,6 +133,7 @@ describe('TopicView', () => {
'topicView.tabs.offlineClients',
'topicView.tabs.messages',
'topicView.tabs.offlineRetransmission',
'topicView.tabs.logs',
])('should activate tab on click', async (tab: string) => {
// given
const user = userEvent.setup();
Expand Down Expand Up @@ -455,4 +457,48 @@ describe('TopicView', () => {
getByText('topicView.confirmationDialog.remove.text'),
).toBeInTheDocument();
});

it('should show logs card on logs tab click', async () => {
// given
const user = userEvent.setup();
const { getByText } = render(TopicView, {
testPinia: createTestingPiniaWithState(),
});

// when
await user.click(getByText('topicView.tabs.logs'));

// then
expect(getByText('logsCard.title')).toBeVisible();
expect(getByText('logsCard.viewLogs')).toBeVisible();
expect(getByText('logsCard.description')).toBeVisible();
});

it('should not show logs tab when kibana is disabled in app config', () => {
// when
const { queryByText } = render(TopicView, {
testPinia: createTestingPinia({
initialState: {
appConfig: {
appConfig: {
...dummyAppConfig,
logs: {
enabled: false,
baseUrl: '',
topicLogsFilter: '',
subscriptionLogsFilter: '',
},
},
loading: false,
error: {
loadConfig: null,
},
},
},
}),
});

// then
expect(queryByText('topicView.tabs.logs')).not.toBeInTheDocument();
});
});
47 changes: 47 additions & 0 deletions hermes-console/src/views/topic/TopicView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -124,13 +124,23 @@
topic.value?.offlineStorage.enabled,
);

const topicLogsUrl = computed(() => {
const logs = configStore.appConfig?.logs;
if (!logs?.baseUrl || !logs?.topicLogsFilter) return '';
return (
logs.baseUrl +
logs.topicLogsFilter.replace('{{topic_name}}', topicName.value)
);
});

const Tab = {
General: 'general',
Schema: 'schema',
Subscriptions: 'subscriptions',
OfflineClients: 'offlineClients',
Messages: 'messages',
OfflineRetransmission: 'offlineRetransmission',
Logs: 'logs',
};
const currentTab = ref<string>(Tab.General);
</script>
Expand Down Expand Up @@ -191,6 +201,13 @@
<v-tab :value="Tab.OfflineRetransmission" class="text-capitalize">
{{ $t('topicView.tabs.offlineRetransmission') }}
</v-tab>
<v-tab
v-if="configStore.appConfig?.logs.enabled"
:value="Tab.Logs"
class="text-capitalize"
>
{{ $t('topicView.tabs.logs') }}
</v-tab>
</v-tabs>
</v-container>

Expand Down Expand Up @@ -277,6 +294,36 @@
/>
</v-container>
</v-tabs-window-item>

<v-tabs-window-item
v-if="configStore.appConfig?.logs.enabled"
:value="Tab.Logs"
>
<v-container class="py-0">
<v-card rounded="lg">
<v-card-item class="border-b">
<div class="d-flex justify-space-between align-start">
<v-card-title class="font-weight-bold">
{{ $t('logsCard.title') }}
</v-card-title>
<v-btn
class="text-none"
prepend-icon="mdi-open-in-new"
target="_blank"
:href="topicLogsUrl"
variant="text"
color="primary"
>
{{ $t('logsCard.viewLogs') }}
</v-btn>
</div>
</v-card-item>
<v-card-text>
{{ $t('logsCard.description') }}
</v-card-text>
</v-card>
</v-container>
</v-tabs-window-item>
</v-tabs-window>
</template>
</v-container>
Expand Down
Loading
Loading