fix: service logs
This commit is contained in:
parent
b4f17ac3c6
commit
9f3732d35b
@ -42,6 +42,7 @@ async function weblate(service: any) {
|
|||||||
`WEBLATE_SITE_DOMAIN@@@$$generate_domain`,
|
`WEBLATE_SITE_DOMAIN@@@$$generate_domain`,
|
||||||
`POSTGRES_USER@@@${postgresqlUser}`,
|
`POSTGRES_USER@@@${postgresqlUser}`,
|
||||||
`POSTGRES_DATABASE@@@${postgresqlDatabase}`,
|
`POSTGRES_DATABASE@@@${postgresqlDatabase}`,
|
||||||
|
`POSTGRES_DB@@@${postgresqlDatabase}`,
|
||||||
`POSTGRES_HOST@@@$$id-postgres`,
|
`POSTGRES_HOST@@@$$id-postgres`,
|
||||||
`POSTGRES_PORT@@@5432`,
|
`POSTGRES_PORT@@@5432`,
|
||||||
`REDIS_HOST@@@$$id-redis`,
|
`REDIS_HOST@@@$$id-redis`,
|
||||||
|
@ -725,18 +725,22 @@ export async function startService(request: FastifyRequest<ServiceStartStop>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Generate files for builds
|
// Generate files for builds
|
||||||
if (template.services[service].build) {
|
if (template.services[service]?.extras?.files?.length > 0) {
|
||||||
if (template.services[service]?.extras?.files?.length > 0) {
|
if (!template.services[service].build) {
|
||||||
let Dockerfile = `
|
template.services[service].build = {
|
||||||
FROM ${template.services[service].image}`
|
context: workdir,
|
||||||
for (const file of template.services[service].extras.files) {
|
dockerfile: `Dockerfile.${service}`
|
||||||
const { source, destination, content } = file;
|
|
||||||
await fs.writeFile(source, content);
|
|
||||||
Dockerfile += `
|
|
||||||
COPY ./${path.basename(source)} ${destination}`
|
|
||||||
}
|
}
|
||||||
await fs.writeFile(`${workdir}/Dockerfile.${service}`, Dockerfile);
|
|
||||||
}
|
}
|
||||||
|
let Dockerfile = `
|
||||||
|
FROM ${template.services[service].image}`
|
||||||
|
for (const file of template.services[service].extras.files) {
|
||||||
|
const { source, destination, content } = file;
|
||||||
|
await fs.writeFile(source, content);
|
||||||
|
Dockerfile += `
|
||||||
|
COPY ./${path.basename(source)} ${destination}`
|
||||||
|
}
|
||||||
|
await fs.writeFile(`${workdir}/Dockerfile.${service}`, Dockerfile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const { volumeMounts } = persistentVolumes(id, persistentStorage, config)
|
const { volumeMounts } = persistentVolumes(id, persistentStorage, config)
|
||||||
|
@ -21,8 +21,8 @@ export default [
|
|||||||
`WEBLATE_ADMIN_PASSWORD=$$secret_weblate_admin_password`,
|
`WEBLATE_ADMIN_PASSWORD=$$secret_weblate_admin_password`,
|
||||||
`POSTGRES_PASSWORD=$$secret_postgres_password`,
|
`POSTGRES_PASSWORD=$$secret_postgres_password`,
|
||||||
`POSTGRES_USER=$$config_postgres_user`,
|
`POSTGRES_USER=$$config_postgres_user`,
|
||||||
`POSTGRES_DATABASE=$$config_postgres_db`,
|
`POSTGRES_DATABASE=$$config_postgres_database`,
|
||||||
`POSTGRES_HOST=$$id-postgres`,
|
`POSTGRES_HOST=$$id-postgresql`,
|
||||||
`POSTGRES_PORT=5432`,
|
`POSTGRES_PORT=5432`,
|
||||||
`REDIS_HOST=$$id-redis`,
|
`REDIS_HOST=$$id-redis`,
|
||||||
],
|
],
|
||||||
@ -59,7 +59,7 @@ export default [
|
|||||||
{
|
{
|
||||||
"id": "$$config_weblate_site_domain",
|
"id": "$$config_weblate_site_domain",
|
||||||
"name": "WEBLATE_SITE_DOMAIN",
|
"name": "WEBLATE_SITE_DOMAIN",
|
||||||
"label": "Weblate domain",
|
"label": "Weblate Domain",
|
||||||
"defaultValue": "$$generate_domain",
|
"defaultValue": "$$generate_domain",
|
||||||
"description": "",
|
"description": "",
|
||||||
},
|
},
|
||||||
@ -69,6 +69,9 @@ export default [
|
|||||||
"label": "Weblate Admin Password",
|
"label": "Weblate Admin Password",
|
||||||
"defaultValue": "$$generate_password",
|
"defaultValue": "$$generate_password",
|
||||||
"description": "",
|
"description": "",
|
||||||
|
"extras": {
|
||||||
|
"isVisibleOnUI": true,
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "$$config_postgres_user",
|
"id": "$$config_postgres_user",
|
||||||
@ -81,16 +84,23 @@ export default [
|
|||||||
"id": "$$secret_postgres_password",
|
"id": "$$secret_postgres_password",
|
||||||
"name": "POSTGRES_PASSWORD",
|
"name": "POSTGRES_PASSWORD",
|
||||||
"label": "PostgreSQL Password",
|
"label": "PostgreSQL Password",
|
||||||
"defaultValue": "",
|
"defaultValue": "$$generate_password",
|
||||||
"description": "",
|
"description": "",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "$$config_postgres_db",
|
"id": "$$config_postgres_db",
|
||||||
"name": "POSTGRES_DB",
|
"name": "POSTGRES_DB",
|
||||||
"label": "PostgreSQL Database",
|
"label": "PostgreSQL Database",
|
||||||
"defaultValue": "hasura",
|
"defaultValue": "weblate",
|
||||||
"description": "",
|
"description": "",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "$$config_postgres_database",
|
||||||
|
"name": "POSTGRES_DATABASE",
|
||||||
|
"label": "PostgreSQL Database",
|
||||||
|
"defaultValue": "$$config_postgres_db",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -102,10 +112,6 @@ export default [
|
|||||||
"services": {
|
"services": {
|
||||||
"$$id": {
|
"$$id": {
|
||||||
"name": "SearXNG",
|
"name": "SearXNG",
|
||||||
"build": {
|
|
||||||
context: "$$workdir",
|
|
||||||
dockerfile: "Dockerfile.$$id"
|
|
||||||
},
|
|
||||||
"depends_on": [
|
"depends_on": [
|
||||||
"$$id-redis"
|
"$$id-redis"
|
||||||
],
|
],
|
||||||
@ -511,10 +517,6 @@ export default [
|
|||||||
"$$id-postgresql": {
|
"$$id-postgresql": {
|
||||||
"name": "PostgreSQL",
|
"name": "PostgreSQL",
|
||||||
"documentation": "Official docs are [here](https://umami.is/docs/getting-started)",
|
"documentation": "Official docs are [here](https://umami.is/docs/getting-started)",
|
||||||
"build": {
|
|
||||||
context: "$$workdir",
|
|
||||||
dockerfile: "Dockerfile.$$id-postgresql"
|
|
||||||
},
|
|
||||||
"depends_on": [],
|
"depends_on": [],
|
||||||
"image": "postgres:12-alpine",
|
"image": "postgres:12-alpine",
|
||||||
"volumes": [
|
"volumes": [
|
||||||
@ -1371,10 +1373,6 @@ export default [
|
|||||||
"$$id-clickhouse": {
|
"$$id-clickhouse": {
|
||||||
"name": "Clickhouse",
|
"name": "Clickhouse",
|
||||||
"documentation": "Taken from https://plausible.io/",
|
"documentation": "Taken from https://plausible.io/",
|
||||||
"build": {
|
|
||||||
context: "$$workdir",
|
|
||||||
dockerfile: "Dockerfile.$$id-clickhouse"
|
|
||||||
},
|
|
||||||
"volumes": [
|
"volumes": [
|
||||||
'$$id-clickhouse-data:/var/lib/clickhouse',
|
'$$id-clickhouse-data:/var/lib/clickhouse',
|
||||||
],
|
],
|
||||||
@ -1455,7 +1453,7 @@ export default [
|
|||||||
"defaultValue": "$$generate_password",
|
"defaultValue": "$$generate_password",
|
||||||
"description": "This is the admin password. Please change it.",
|
"description": "This is the admin password. Please change it.",
|
||||||
"extras": {
|
"extras": {
|
||||||
"isVisibleOnUI": true
|
"isVisibleOnUI": true,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -157,9 +157,9 @@ export async function parseAndFindServiceTemplates(service: any, workdir?: strin
|
|||||||
const { name, value } = setting
|
const { name, value } = setting
|
||||||
const regex = new RegExp(`\\$\\$config_${name}\\"`, 'gi')
|
const regex = new RegExp(`\\$\\$config_${name}\\"`, 'gi')
|
||||||
if (service.fqdn && value === '$$generate_fqdn') {
|
if (service.fqdn && value === '$$generate_fqdn') {
|
||||||
parsedTemplate = JSON.parse(JSON.stringify(parsedTemplate).replaceAll(regex, service.fqdn+ "\""))
|
parsedTemplate = JSON.parse(JSON.stringify(parsedTemplate).replaceAll(regex, service.fqdn + "\""))
|
||||||
} else if (service.fqdn && value === '$$generate_domain') {
|
} else if (service.fqdn && value === '$$generate_domain') {
|
||||||
parsedTemplate = JSON.parse(JSON.stringify(parsedTemplate).replaceAll(regex, getDomain(service.fqdn)+ "\""))
|
parsedTemplate = JSON.parse(JSON.stringify(parsedTemplate).replaceAll(regex, getDomain(service.fqdn) + "\""))
|
||||||
} else {
|
} else {
|
||||||
parsedTemplate = JSON.parse(JSON.stringify(parsedTemplate).replaceAll(regex, value + "\""))
|
parsedTemplate = JSON.parse(JSON.stringify(parsedTemplate).replaceAll(regex, value + "\""))
|
||||||
|
|
||||||
@ -363,7 +363,7 @@ export async function getServiceUsage(request: FastifyRequest<OnlyId>) {
|
|||||||
}
|
}
|
||||||
export async function getServiceLogs(request: FastifyRequest<GetServiceLogs>) {
|
export async function getServiceLogs(request: FastifyRequest<GetServiceLogs>) {
|
||||||
try {
|
try {
|
||||||
const { id } = request.params;
|
const { id, containerId } = request.params;
|
||||||
let { since = 0 } = request.query
|
let { since = 0 } = request.query
|
||||||
if (since !== 0) {
|
if (since !== 0) {
|
||||||
since = day(since).unix();
|
since = day(since).unix();
|
||||||
@ -374,10 +374,8 @@ export async function getServiceLogs(request: FastifyRequest<GetServiceLogs>) {
|
|||||||
});
|
});
|
||||||
if (destinationDockerId) {
|
if (destinationDockerId) {
|
||||||
try {
|
try {
|
||||||
// const found = await checkContainer({ dockerId, container: id })
|
|
||||||
// if (found) {
|
|
||||||
const { default: ansi } = await import('strip-ansi')
|
const { default: ansi } = await import('strip-ansi')
|
||||||
const { stdout, stderr } = await executeDockerCmd({ dockerId, command: `docker logs --since ${since} --tail 5000 --timestamps ${id}` })
|
const { stdout, stderr } = await executeDockerCmd({ dockerId, command: `docker logs --since ${since} --tail 5000 --timestamps ${containerId}` })
|
||||||
const stripLogsStdout = stdout.toString().split('\n').map((l) => ansi(l)).filter((a) => a);
|
const stripLogsStdout = stdout.toString().split('\n').map((l) => ansi(l)).filter((a) => a);
|
||||||
const stripLogsStderr = stderr.toString().split('\n').map((l) => ansi(l)).filter((a) => a);
|
const stripLogsStderr = stderr.toString().split('\n').map((l) => ansi(l)).filter((a) => a);
|
||||||
const logs = stripLogsStderr.concat(stripLogsStdout)
|
const logs = stripLogsStderr.concat(stripLogsStdout)
|
||||||
@ -385,7 +383,10 @@ export async function getServiceLogs(request: FastifyRequest<GetServiceLogs>) {
|
|||||||
return { logs: sortedLogs }
|
return { logs: sortedLogs }
|
||||||
// }
|
// }
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const { statusCode } = error;
|
const { statusCode, stderr } = error;
|
||||||
|
if (stderr.startsWith('Error: No such container')) {
|
||||||
|
return { logs: [], noContainer: true }
|
||||||
|
}
|
||||||
if (statusCode === 404) {
|
if (statusCode === 404) {
|
||||||
return {
|
return {
|
||||||
logs: []
|
logs: []
|
||||||
|
@ -70,7 +70,8 @@ const root: FastifyPluginAsync = async (fastify): Promise<void> => {
|
|||||||
fastify.post<SaveServiceDestination>('/:id/configuration/destination', async (request, reply) => await saveServiceDestination(request, reply));
|
fastify.post<SaveServiceDestination>('/:id/configuration/destination', async (request, reply) => await saveServiceDestination(request, reply));
|
||||||
|
|
||||||
fastify.get<OnlyId>('/:id/usage', async (request) => await getServiceUsage(request));
|
fastify.get<OnlyId>('/:id/usage', async (request) => await getServiceUsage(request));
|
||||||
fastify.get<GetServiceLogs>('/:id/logs', async (request) => await getServiceLogs(request));
|
// fastify.get<GetServiceLogs>('/:id/logs', async (request) => await getServiceLogs(request));
|
||||||
|
fastify.get<GetServiceLogs>('/:id/logs/:containerId', async (request) => await getServiceLogs(request));
|
||||||
|
|
||||||
fastify.post<ServiceStartStop>('/:id/start', async (request) => await startService(request));
|
fastify.post<ServiceStartStop>('/:id/start', async (request) => await startService(request));
|
||||||
fastify.post<ServiceStartStop>('/:id/:type/start', async (request) => await startService(request));
|
fastify.post<ServiceStartStop>('/:id/:type/start', async (request) => await startService(request));
|
||||||
|
@ -15,9 +15,13 @@ export interface SaveServiceDestination extends OnlyId {
|
|||||||
destinationId: string
|
destinationId: string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export interface GetServiceLogs extends OnlyId {
|
export interface GetServiceLogs{
|
||||||
|
Params: {
|
||||||
|
id: string,
|
||||||
|
containerId: string
|
||||||
|
},
|
||||||
Querystring: {
|
Querystring: {
|
||||||
since: number
|
since: number,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export interface SaveServiceSettings extends OnlyId {
|
export interface SaveServiceSettings extends OnlyId {
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { page } from '$app/stores';
|
import { page } from '$app/stores';
|
||||||
import { get } from '$lib/api';
|
import { get } from '$lib/api';
|
||||||
import { t } from '$lib/translations';
|
|
||||||
import { errorNotification } from '$lib/common';
|
import { errorNotification } from '$lib/common';
|
||||||
import { onMount, onDestroy } from 'svelte';
|
import { onMount, onDestroy } from 'svelte';
|
||||||
import Tooltip from '$lib/components/Tooltip.svelte';
|
|
||||||
|
|
||||||
let application: any = {};
|
let application: any = {};
|
||||||
let logsLoading = false;
|
let logsLoading = false;
|
||||||
@ -137,12 +135,13 @@
|
|||||||
{:else}
|
{:else}
|
||||||
<div class="relative w-full" />
|
<div class="relative w-full" />
|
||||||
<div class="flex justify-start sticky space-x-2 pb-2">
|
<div class="flex justify-start sticky space-x-2 pb-2">
|
||||||
<button
|
{#if loadLogsInterval}
|
||||||
on:click={followBuild}
|
<button id="streaming" class="btn btn-sm bg-transparent border-none loading"
|
||||||
class="btn btn-sm bg-coollabs"
|
>Streaming logs</button
|
||||||
class:bg-coolgray-300={followingLogs}
|
>
|
||||||
class:text-applications={followingLogs}
|
{/if}
|
||||||
>
|
<div class="flex-1" />
|
||||||
|
<button on:click={followBuild} class="btn btn-sm " class:bg-coollabs={followingLogs}>
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
class="w-6 h-6 mr-2"
|
class="w-6 h-6 mr-2"
|
||||||
@ -161,11 +160,6 @@
|
|||||||
</svg>
|
</svg>
|
||||||
{followingLogs ? 'Following Logs...' : 'Follow Logs'}
|
{followingLogs ? 'Following Logs...' : 'Follow Logs'}
|
||||||
</button>
|
</button>
|
||||||
{#if loadLogsInterval}
|
|
||||||
<button id="streaming" class="btn btn-sm bg-transparent border-none loading"
|
|
||||||
>Streaming logs</button
|
|
||||||
>
|
|
||||||
{/if}
|
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
bind:this={logsEl}
|
bind:this={logsEl}
|
||||||
|
@ -187,36 +187,30 @@
|
|||||||
<div class="title lg:pb-10">
|
<div class="title lg:pb-10">
|
||||||
<div class="flex justify-center items-center space-x-2">
|
<div class="flex justify-center items-center space-x-2">
|
||||||
<div>
|
<div>
|
||||||
{#if $page.url.pathname === `/services/${id}/secrets`}
|
{#if $page.url.pathname === `/services/${id}/configuration/type`}
|
||||||
Secrets
|
|
||||||
{:else if $page.url.pathname === `/services/${id}/storages`}
|
|
||||||
Persistent Storages
|
|
||||||
{:else if $page.url.pathname === `/services/${id}/logs`}
|
|
||||||
Service Logs
|
|
||||||
{:else if $page.url.pathname === `/services/${id}/configuration/type`}
|
|
||||||
Select a Service Type
|
Select a Service Type
|
||||||
{:else if $page.url.pathname === `/services/${id}/configuration/version`}
|
{:else if $page.url.pathname === `/services/${id}/configuration/version`}
|
||||||
Select a Service Version
|
Select a Service Version
|
||||||
{:else if $page.url.pathname === `/services/${id}/configuration/destination`}
|
{:else if $page.url.pathname === `/services/${id}/configuration/destination`}
|
||||||
Select a Destination
|
Select a Destination
|
||||||
{:else}
|
{:else}
|
||||||
Configurations
|
<div class="flex justify-center items-center space-x-2">
|
||||||
|
<div>Configurations</div>
|
||||||
|
<div
|
||||||
|
class="badge badge-lg rounded uppercase"
|
||||||
|
class:text-green-500={$status.service.overallStatus === 'healthy'}
|
||||||
|
class:text-yellow-400={$status.service.overallStatus === 'degraded'}
|
||||||
|
class:text-red-500={$status.service.overallStatus === 'stopped'}
|
||||||
|
>
|
||||||
|
{$status.service.overallStatus === 'healthy'
|
||||||
|
? 'Healthy'
|
||||||
|
: $status.service.overallStatus === 'degraded'
|
||||||
|
? 'Degraded'
|
||||||
|
: 'Stopped'}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{#if !$page.url.pathname.startsWith(`/services/${id}/configuration/`)}
|
|
||||||
<div
|
|
||||||
class="badge badge-lg rounded uppercase"
|
|
||||||
class:text-green-500={$status.service.overallStatus === 'healthy'}
|
|
||||||
class:text-yellow-400={$status.service.overallStatus === 'degraded'}
|
|
||||||
class:text-red-500={$status.service.overallStatus === 'stopped'}
|
|
||||||
>
|
|
||||||
{$status.service.overallStatus === 'healthy'
|
|
||||||
? 'Healthy'
|
|
||||||
: $status.service.overallStatus === 'degraded'
|
|
||||||
? 'Degraded'
|
|
||||||
: 'Stopped'}
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{#if $page.url.pathname.startsWith(`/services/${id}/configuration/`)}
|
{#if $page.url.pathname.startsWith(`/services/${id}/configuration/`)}
|
||||||
@ -310,11 +304,11 @@
|
|||||||
on:click={stopService}
|
on:click={stopService}
|
||||||
type="submit"
|
type="submit"
|
||||||
disabled={!$isDeploymentEnabled}
|
disabled={!$isDeploymentEnabled}
|
||||||
class="btn btn-sm btn-error gap-2"
|
class="btn btn-sm gap-2"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
class="w-6 h-6 "
|
class="w-6 h-6 text-error"
|
||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
stroke-width="1.5"
|
stroke-width="1.5"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
@ -381,7 +375,7 @@
|
|||||||
<Menu {service} />
|
<Menu {service} />
|
||||||
</nav>
|
</nav>
|
||||||
{/if}
|
{/if}
|
||||||
<div class="pt-0 col-span-0 lg:col-span-3 pb-24">
|
<div class="pt-0 col-span-0 lg:col-span-3 pb-24 px-4 lg:px-0">
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,11 +1,8 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { page } from '$app/stores';
|
import { page } from '$app/stores';
|
||||||
import LoadingLogs from './_Loading.svelte';
|
|
||||||
import { get } from '$lib/api';
|
import { get } from '$lib/api';
|
||||||
import { t } from '$lib/translations';
|
|
||||||
import { errorNotification } from '$lib/common';
|
import { errorNotification } from '$lib/common';
|
||||||
import { onDestroy, onMount } from 'svelte';
|
import { onDestroy, onMount } from 'svelte';
|
||||||
import Tooltip from '$lib/components/Tooltip.svelte';
|
|
||||||
|
|
||||||
let service: any = {};
|
let service: any = {};
|
||||||
let template: any = null;
|
let template: any = null;
|
||||||
@ -18,41 +15,32 @@
|
|||||||
let logsEl: any;
|
let logsEl: any;
|
||||||
let position = 0;
|
let position = 0;
|
||||||
let selectedService: any = null;
|
let selectedService: any = null;
|
||||||
|
let noContainer = false;
|
||||||
|
|
||||||
const { id } = $page.params;
|
const { id } = $page.params;
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
const response = await get(`/services/${id}`);
|
const response = await get(`/services/${id}`);
|
||||||
template = response.template;
|
template = response.template;
|
||||||
service = response.service;
|
service = response.service;
|
||||||
loadAllLogs();
|
|
||||||
loadLogsInterval = setInterval(() => {
|
|
||||||
loadLogs();
|
|
||||||
}, 1000);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
onDestroy(() => {
|
onDestroy(() => {
|
||||||
clearInterval(loadLogsInterval);
|
clearInterval(loadLogsInterval);
|
||||||
clearInterval(followingInterval);
|
clearInterval(followingInterval);
|
||||||
});
|
});
|
||||||
async function loadAllLogs() {
|
|
||||||
try {
|
|
||||||
logsLoading = true;
|
|
||||||
const data: any = await get(`/services/${id}/logs`);
|
|
||||||
if (data?.logs) {
|
|
||||||
lastLog = data.logs[data.logs.length - 1];
|
|
||||||
logs = data.logs;
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
return errorNotification(error);
|
|
||||||
} finally {
|
|
||||||
logsLoading = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async function loadLogs() {
|
async function loadLogs() {
|
||||||
if (logsLoading) return;
|
if (logsLoading) return;
|
||||||
try {
|
try {
|
||||||
const newLogs: any = await get(`/services/${id}/logs?since=${lastLog?.split(' ')[0] || 0}`);
|
const newLogs: any = await get(
|
||||||
|
`/services/${id}/logs/${selectedService}?since=${lastLog?.split(' ')[0] || 0}`
|
||||||
|
);
|
||||||
|
if (newLogs.noContainer) {
|
||||||
|
noContainer = true;
|
||||||
|
} else {
|
||||||
|
noContainer = false;
|
||||||
|
}
|
||||||
if (newLogs?.logs && newLogs.logs[newLogs.logs.length - 1] !== logs[logs.length - 1]) {
|
if (newLogs?.logs && newLogs.logs[newLogs.logs.length - 1] !== logs[logs.length - 1]) {
|
||||||
logs = logs.concat(newLogs.logs);
|
logs = logs.concat(newLogs.logs);
|
||||||
lastLog = newLogs.logs[newLogs.logs.length - 1];
|
lastLog = newLogs.logs[newLogs.logs.length - 1];
|
||||||
@ -100,9 +88,14 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if template}
|
<div class="mx-auto w-full">
|
||||||
<div class="flex gap-2 lg:gap-8 pb-4">
|
<div class="flex flex-row border-b border-coolgray-500 mb-6 space-x-2">
|
||||||
{#each Object.keys(template.services) as service}
|
<div class="title font-bold pb-3">Service Logs</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex gap-2 lg:gap-8 pb-4">
|
||||||
|
{#if template}
|
||||||
|
{#each Object.keys(template) as service}
|
||||||
<button
|
<button
|
||||||
on:click={() => selectService(service, true)}
|
on:click={() => selectService(service, true)}
|
||||||
class:bg-primary={selectedService === service}
|
class:bg-primary={selectedService === service}
|
||||||
@ -112,21 +105,25 @@
|
|||||||
{service}</button
|
{service}</button
|
||||||
>
|
>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
{/if}
|
||||||
{/if}
|
</div>
|
||||||
|
|
||||||
{#if selectedService}
|
{#if selectedService}
|
||||||
<div class="flex flex-row justify-center space-x-2">
|
<div class="flex flex-row justify-center space-x-2">
|
||||||
{#if logs.length === 0}
|
{#if logs.length === 0}
|
||||||
<div class="text-xl font-bold tracking-tighter">{$t('application.build.waiting_logs')}</div>
|
{#if noContainer}
|
||||||
|
<div class="text-xl font-bold tracking-tighter">Container not found / exited.</div>
|
||||||
|
{/if}
|
||||||
{:else}
|
{:else}
|
||||||
<div class="relative w-full">
|
<div class="relative w-full">
|
||||||
<div class="flex justify-start sticky space-x-2 pb-2">
|
<div class="flex justify-start sticky space-x-2 pb-2">
|
||||||
<button
|
{#if loadLogsInterval}
|
||||||
on:click={followBuild}
|
<button id="streaming" class="btn btn-sm bg-transparent border-none loading"
|
||||||
class="btn btn-sm bg-coollabs"
|
>Streaming logs</button
|
||||||
class:bg-coolgray-300={followingLogs}
|
>
|
||||||
class:text-applications={followingLogs}
|
{/if}
|
||||||
>
|
<div class="flex-1" />
|
||||||
|
<button on:click={followBuild} class="btn btn-sm " class:bg-coollabs={followingLogs}>
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
class="w-6 h-6 mr-2"
|
class="w-6 h-6 mr-2"
|
||||||
@ -145,11 +142,6 @@
|
|||||||
</svg>
|
</svg>
|
||||||
{followingLogs ? 'Following Logs...' : 'Follow Logs'}
|
{followingLogs ? 'Following Logs...' : 'Follow Logs'}
|
||||||
</button>
|
</button>
|
||||||
{#if loadLogsInterval}
|
|
||||||
<button id="streaming" class="btn btn-sm bg-transparent border-none loading"
|
|
||||||
>Streaming logs</button
|
|
||||||
>
|
|
||||||
{/if}
|
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
bind:this={logsEl}
|
bind:this={logsEl}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user