You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ma...@apache.org on 2023/07/23 16:55:57 UTC
[camel-karavan] 02/02: Log in UI with Docker #817
This is an automated email from the ASF dual-hosted git repository.
marat pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-karavan.git
commit f90b524b1d1b54d4c1871b95a9253daa1f623f03
Author: Marat Gubaidullin <ma...@gmail.com>
AuthorDate: Sun Jul 23 12:55:41 2023 -0400
Log in UI with Docker #817
---
.../apache/camel/karavan/api/LogWatchResource.java | 33 +++++++++++++++++++---
.../camel/karavan/docker/DockerEventListener.java | 2 +-
.../apache/camel/karavan/docker/DockerService.java | 6 ++--
.../apache/camel/karavan/docker/LogCallback.java | 11 ++++----
.../apache/camel/karavan/service/EventService.java | 1 -
.../camel/karavan/service/ProjectService.java | 9 +++++-
.../camel/karavan/service/ScheduledService.java | 17 +++++++++--
.../src/main/resources/application.properties | 7 +++--
.../src/main/webui/src/api/ProjectStore.ts | 17 ++++++++---
.../src/main/webui/src/project/ProjectToolbar.tsx | 9 +-----
.../camel/karavan/headless/HeadlessService.java | 2 +-
.../src/main/resources/application.properties | 2 +-
12 files changed, 80 insertions(+), 36 deletions(-)
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/LogWatchResource.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/LogWatchResource.java
index 3a235592..40cbc79a 100644
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/LogWatchResource.java
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/LogWatchResource.java
@@ -17,10 +17,15 @@
package org.apache.camel.karavan.api;
import io.fabric8.kubernetes.client.dsl.LogWatch;
+import io.smallrye.context.api.ManagedExecutorConfig;
+import io.smallrye.context.api.NamedInstance;
+import org.apache.camel.karavan.docker.DockerService;
+import org.apache.camel.karavan.docker.LogCallback;
import org.apache.camel.karavan.infinispan.InfinispanService;
import org.apache.camel.karavan.kubernetes.KubernetesService;
import org.apache.camel.karavan.shared.ConfigService;
import org.eclipse.microprofile.context.ManagedExecutor;
+import org.eclipse.microprofile.context.ThreadContext;
import org.jboss.logging.Logger;
import javax.inject.Inject;
@@ -30,11 +35,13 @@ import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.sse.Sse;
import javax.ws.rs.sse.SseEventSink;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
+import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
@Path("/api/logwatch")
@@ -47,9 +54,11 @@ public class LogWatchResource {
KubernetesService kubernetesService;
@Inject
- InfinispanService infinispanService;
+ DockerService dockerService;
@Inject
+ @ManagedExecutorConfig()
+ @NamedInstance("logExecutor")
ManagedExecutor managedExecutor;
@GET
@@ -57,19 +66,35 @@ public class LogWatchResource {
@Path("/{type}/{name}")
public void eventSourcing(@PathParam("type") String type,
@PathParam("name") String name,
+ @Context SecurityContext securityContext,
@Context SseEventSink eventSink,
- @Context Sse sse
- ) {
+ @Context Sse sse) {
+
managedExecutor.execute(() -> {
LOGGER.info("LogWatch for " + name + " starting...");
if (ConfigService.inKubernetes()) {
getKubernetesLogs(type, name, eventSink, sse);
} else {
-// infinispanService.sendDevModeCommand(DevModeCommand.createForContainer(DevModeCommandName.LOG, name));
+ getDockerLogs(type, name, eventSink, sse);
}
});
}
+ private void getDockerLogs(String type, String name, SseEventSink eventSink, Sse sse) {
+ LOGGER.info("LogCallback for " + name + " starting");
+ try (SseEventSink sink = eventSink) {
+ LogCallback logCallback = new LogCallback(line -> {
+ sink.send(sse.newEvent(line));
+ });
+ dockerService.logContainer(name, logCallback);
+ logCallback.close();
+ sink.close();
+ LOGGER.info("LogCallback for " + name + " closed");
+ } catch (Exception e) {
+ LOGGER.error(e.getMessage());
+ }
+ }
+
private void getKubernetesLogs(String type, String name, SseEventSink eventSink, Sse sse) {
try (SseEventSink sink = eventSink) {
LogWatch logWatch = type.equals("container")
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerEventListener.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerEventListener.java
index 0ee8000a..8d4c9cc3 100644
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerEventListener.java
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerEventListener.java
@@ -159,7 +159,7 @@ public class DockerEventListener implements ResultCallback<Event> {
@Override
public void close() throws IOException {
- LOGGER.error("DockerEventListener close");
+ LOGGER.info("DockerEventListener close");
}
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerService.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerService.java
index 3b380749..9f1f4198 100644
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerService.java
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerService.java
@@ -120,6 +120,7 @@ public class DockerService {
public void deleteKaravanHeadlessContainer() {
try {
+ stopContainer(KARAVAN_CONTAINER_NAME);
deleteContainer(KARAVAN_CONTAINER_NAME);
} catch (Exception e) {
LOGGER.error(e.getMessage());
@@ -252,11 +253,10 @@ public class DockerService {
startContainer(name);
}
- public LogCallback logContainer(String containerName) {
+ public void logContainer(String containerName, LogCallback callback) {
try {
Container container = getContainerByName(containerName);
if (container != null) {
- LogCallback callback = new LogCallback(eventBus);
getDockerClient().logContainerCmd(container.getId())
.withStdOut(true)
.withStdErr(true)
@@ -265,12 +265,10 @@ public class DockerService {
.withTailAll()
.exec(callback);
callback.awaitCompletion();
- return callback;
}
} catch (Exception e) {
LOGGER.error(e.getMessage());
}
- return null;
}
public void stopContainer(String name) {
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/LogCallback.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/LogCallback.java
index a05efb31..bd0de584 100644
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/LogCallback.java
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/LogCallback.java
@@ -2,19 +2,20 @@ package org.apache.camel.karavan.docker;
import com.github.dockerjava.api.async.ResultCallback;
import com.github.dockerjava.api.model.Frame;
-import io.vertx.core.eventbus.EventBus;
+
+import java.util.function.Consumer;
public class LogCallback extends ResultCallback.Adapter<Frame> {
- private final EventBus eventBus;
+ private final Consumer<String> action;
- public LogCallback(EventBus eventBus) {
- this.eventBus = eventBus;
+ public LogCallback(Consumer<String> action) {
+ this.action = action;
}
@Override
public void onNext(Frame frame) {
- System.out.println(new String(frame.getPayload()));
+ action.accept(new String(frame.getPayload()));
}
}
\ No newline at end of file
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/EventService.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/EventService.java
index fe48ad1c..4d6f0b7a 100644
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/EventService.java
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/EventService.java
@@ -49,7 +49,6 @@ public class EventService {
infinispanService.start(false);
infinispanService.clearAllStatuses();
if (!ConfigService.inKubernetes()) {
- dockerService.deleteKaravanHeadlessContainer();
dockerService.startKaravanHeadlessContainer();
dockerService.collectContainersStatuses();
}
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/ProjectService.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/ProjectService.java
index 87c7dbe4..815eab38 100644
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/ProjectService.java
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/ProjectService.java
@@ -36,6 +36,7 @@ import javax.enterprise.inject.Default;
import javax.inject.Inject;
import java.time.Instant;
import java.util.List;
+import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;
import static org.apache.camel.karavan.shared.EventType.IMPORT_PROJECTS;
@@ -47,6 +48,9 @@ public class ProjectService implements HealthCheck{
private static final Logger LOGGER = Logger.getLogger(ProjectService.class.getName());
+ @ConfigProperty(name = "karavan.git.pull.interval")
+ String gitPullInterval;
+
@Inject
InfinispanService infinispanService;
@@ -91,6 +95,7 @@ public class ProjectService implements HealthCheck{
void importCommits() {
LOGGER.info("Import commits...");
gitService.getAllCommits().forEach(commitInfo -> {
+ System.out.println(commitInfo.getCommitId() + " " + Instant.ofEpochSecond(commitInfo.getTime()).toString());
infinispanService.saveCommit(commitInfo.getCommitId(), commitInfo.getTime());
infinispanService.saveLastCommit(commitInfo.getCommitId());
});
@@ -103,7 +108,9 @@ public class ProjectService implements HealthCheck{
}
addTemplatesProject();
addServicesProject();
- importCommits();
+ if (!Objects.equals("disabled", gitPullInterval.toLowerCase()) && !Objects.equals("off", gitPullInterval.toLowerCase())) {
+ importCommits();
+ }
}
private void importAllProjects() {
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/ScheduledService.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/ScheduledService.java
index d7f32e95..7886a86d 100644
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/ScheduledService.java
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/ScheduledService.java
@@ -18,6 +18,7 @@ package org.apache.camel.karavan.service;
import io.quarkus.scheduler.Scheduled;
import org.apache.camel.karavan.docker.DockerService;
+import org.apache.camel.karavan.infinispan.InfinispanService;
import org.apache.camel.karavan.shared.ConfigService;
import org.jboss.logging.Logger;
@@ -38,12 +39,22 @@ public class ScheduledService {
@Inject
CamelService camelService;
- @Scheduled(every = "{karavan.container.statistics.container}", concurrentExecution = Scheduled.ConcurrentExecution.SKIP)
+ @Inject
+ InfinispanService infinispanService;
+
+ @Scheduled(every = "{karavan.container.statistics.interval}", concurrentExecution = Scheduled.ConcurrentExecution.SKIP)
void collectContainersStats() {
dockerService.collectContainersStats();
}
- @Scheduled(every = "{karavan.camel.status.pull-interval}", concurrentExecution = Scheduled.ConcurrentExecution.SKIP)
+ @Scheduled(every = "{karavan.container.infinispan.interval}", concurrentExecution = Scheduled.ConcurrentExecution.SKIP)
+ void checkInfinispanHealth() {
+ if (!infinispanService.isReady()) {
+ dockerService.checkInfinispanHealth();
+ }
+ }
+
+ @Scheduled(every = "{karavan.camel.status.interval}", concurrentExecution = Scheduled.ConcurrentExecution.SKIP)
void collectCamelStatuses() {
LOGGER.info("Collect info statuses");
if (ConfigService.inKubernetes()) {
@@ -52,7 +63,7 @@ public class ScheduledService {
}
}
- @Scheduled(every = "{karavan.git.pull-interval}", concurrentExecution = Scheduled.ConcurrentExecution.SKIP)
+ @Scheduled(every = "{karavan.git.pull.interval}", concurrentExecution = Scheduled.ConcurrentExecution.SKIP)
void pullCommitsFromGit() {
projectService.pullCommits();
}
diff --git a/karavan-web/karavan-app/src/main/resources/application.properties b/karavan-web/karavan-app/src/main/resources/application.properties
index 76045045..2cee473c 100644
--- a/karavan-web/karavan-app/src/main/resources/application.properties
+++ b/karavan-web/karavan-app/src/main/resources/application.properties
@@ -3,8 +3,9 @@ karavan.environment=dev
karavan.environments=dev,test,prod
karavan.default-runtime=quarkus
karavan.runtimes=quarkus,spring-boot
-karavan.camel.status.pull-interval=off
-karavan.container.statistics.container=3s
+karavan.camel.status.interval=off
+karavan.container.statistics.interval=3s
+karavan.container.infinispan.interval=5s
karavan.devmode.image=ghcr.io/apache/camel-karavan-runner:3.21.1-snapshot
karavan.headless.image=entropy1/karavan-headless:3.21.1-SNAPSHOT
@@ -13,7 +14,7 @@ karavan.git.repository=${GIT_REPOSITORY}
karavan.git.username=${GIT_USERNAME}
karavan.git.password=${GIT_TOKEN}
karavan.git.branch=main
-karavan.git.pull-interval=disabled
+karavan.git.pull.interval=disabled
# Infinispan container config in Docker
infinispan.image=quay.io/infinispan/server:14.0.6.Final
diff --git a/karavan-web/karavan-app/src/main/webui/src/api/ProjectStore.ts b/karavan-web/karavan-app/src/main/webui/src/api/ProjectStore.ts
index 9a891b3e..b4930ead 100644
--- a/karavan-web/karavan-app/src/main/webui/src/api/ProjectStore.ts
+++ b/karavan-web/karavan-app/src/main/webui/src/api/ProjectStore.ts
@@ -191,10 +191,16 @@ export const useLogStore = create<LogState>((set) => ({
set({data: data})
},
addData: (data: string) => {
- set((state: LogState) => ({data: state.data.concat('\n').concat(data)}))
+ set((state: LogState) => {
+ const delimiter = state.data.endsWith('\n') ? '' : '\n';
+ return ({data: state.data.concat(delimiter, data)})
+ })
},
addDataAsync: async (data: string) => {
- set((state: LogState) => ({data: state.data.concat('\n').concat(data)}))
+ set((state: LogState) => {
+ const delimiter = state.data.endsWith('\n') ? '' : '\n';
+ return ({data: state.data.concat(delimiter, data)})
+ })
},
currentLine: 0,
setCurrentLine: (currentLine: number) => {
@@ -217,8 +223,11 @@ console.log("Start log subscriber");
const sub = ProjectEventBus.onLog()?.subscribe((result: ["add" | "set", string]) => {
if (result[0] === 'add') {
unstable_batchedUpdates(() => {
- useLogStore.setState((state: LogState) =>
- ({data: state.data ? state.data.concat('\n').concat(result[1]) : result[1], currentLine: state.currentLine+1}))
+ useLogStore.setState((state: LogState) => {
+ const delimiter = state.data.endsWith('\n') ? '' : '\n';
+ const newData = state.data ? state.data.concat(delimiter, result[1]) : result[1]
+ return ({data: newData, currentLine: state.currentLine+1});
+ })
})
}
else if (result[0] === 'set') {
diff --git a/karavan-web/karavan-app/src/main/webui/src/project/ProjectToolbar.tsx b/karavan-web/karavan-app/src/main/webui/src/project/ProjectToolbar.tsx
index 4e6c5704..2f639228 100644
--- a/karavan-web/karavan-app/src/main/webui/src/project/ProjectToolbar.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/project/ProjectToolbar.tsx
@@ -4,13 +4,11 @@ import {
Checkbox,
Flex,
FlexItem,
- Label,
ToggleGroup,
ToggleGroupItem,
Toolbar,
ToolbarContent,
- Tooltip,
- TooltipPosition
+ Tooltip
} from '@patternfly/react-core';
import '../designer/karavan.css';
import DownloadImageIcon from "@patternfly/react-icons/dist/esm/icons/image-icon";
@@ -79,11 +77,6 @@ export const ProjectToolbar = (props: Props) => {
return <Toolbar id="toolbar-group-types">
<ToolbarContent>
<Flex className="toolbar" direction={{default: "row"}} alignItems={{default: "alignItemsCenter"}}>
- {isJava() && <FlexItem>
- <Tooltip content="File size" position={TooltipPosition.bottom}>
- <Label>{file?.code?.length}</Label>
- </Tooltip>
- </FlexItem>}
{isRunnable() && <DevModeToolbar reloadOnly={true}/>}
{isYaml() && <FlexItem>
<ToggleGroup>
diff --git a/karavan-web/karavan-headless/src/main/java/org/apache/camel/karavan/headless/HeadlessService.java b/karavan-web/karavan-headless/src/main/java/org/apache/camel/karavan/headless/HeadlessService.java
index 01b00da7..e6f8624f 100644
--- a/karavan-web/karavan-headless/src/main/java/org/apache/camel/karavan/headless/HeadlessService.java
+++ b/karavan-web/karavan-headless/src/main/java/org/apache/camel/karavan/headless/HeadlessService.java
@@ -42,7 +42,7 @@ public class HeadlessService {
infinispanService.clearAllStatuses();
}
- @Scheduled(every = "{karavan.camel.status.pull-interval}", concurrentExecution = Scheduled.ConcurrentExecution.SKIP)
+ @Scheduled(every = "{karavan.camel.status.interval}", concurrentExecution = Scheduled.ConcurrentExecution.SKIP)
void collectCamelStatuses() {
LOGGER.info("Collect info statuses");
// collect Camel statuses
diff --git a/karavan-web/karavan-headless/src/main/resources/application.properties b/karavan-web/karavan-headless/src/main/resources/application.properties
index dedfb854..ec2c2f7c 100644
--- a/karavan-web/karavan-headless/src/main/resources/application.properties
+++ b/karavan-web/karavan-headless/src/main/resources/application.properties
@@ -1,5 +1,5 @@
karavan.environment=dev
-karavan.camel.status.pull-interval=3s
+karavan.camel.status.interval=3s
infinispan.hosts=infinispan:11222
infinispan.username=admin