From 3e6e127191389cee17013d3239d923989b637bbb Mon Sep 17 00:00:00 2001 From: Lerb123 Date: Mon, 11 May 2026 11:47:26 -0400 Subject: [PATCH 1/6] feat: Implement Loki appender for Karaf event bus --- .../org.apache.plc4x.merlot.archiver/pom.xml | 40 +++- .../org.apache.plc4x.merlot.loki.appender.cfg | 41 ++++ .../archiver/impl/MerlotLokiAppender.java | 178 ++++++++++++++++++ .../OSGI-INF/blueprint/archiver-service.xml | 35 +++- .../archiver/test/MerlotLokiAppenderTest.java | 75 ++++++++ .../src/main/feature/feature.xml | 2 +- .../org.apache.plc4x.merlot.kafka/pom.xml | 1 + plc4j/tools/merlot/pom.xml | 1 + 8 files changed, 361 insertions(+), 12 deletions(-) create mode 100644 plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/main/cfg/org.apache.plc4x.merlot.loki.appender.cfg create mode 100644 plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/main/java/org/apache/plc4x/merlot/archiver/impl/MerlotLokiAppender.java create mode 100644 plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/test/java/org/apache/plc4x/merlot/archiver/test/MerlotLokiAppenderTest.java diff --git a/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/pom.xml b/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/pom.xml index 878cce8a..8e71af28 100644 --- a/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/pom.xml +++ b/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/pom.xml @@ -21,10 +21,10 @@ 4.0.0 - merlot - org.apache.plc4x - 0.13.0-SNAPSHOT - + merlot + org.apache.plc4x + 0.13.0-SNAPSHOT + org.apache.plc4x.merlot.archiver org.apache.plc4x.merlot.archiver @@ -107,10 +107,10 @@ src/main/cfg/org.apache.plc4x.merlot.collector.log-alarm.cfg cfg5 - + @@ -276,5 +276,31 @@ 1.18.42 jar + + org.apache.karaf.decanter + org.apache.karaf.decanter.api + 2.10.0 + bundle + + + org.mockito + mockito-junit-jupiter + 5.5.0 + test + + + + org.wiremock + wiremock + 3.13.1 + test + + + de.mkammerer.wiremock-junit5 + wiremock-junit5 + 1.1.0 + test + jar + diff --git a/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/main/cfg/org.apache.plc4x.merlot.loki.appender.cfg b/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/main/cfg/org.apache.plc4x.merlot.loki.appender.cfg new file mode 100644 index 00000000..2aa13fe3 --- /dev/null +++ b/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/main/cfg/org.apache.plc4x.merlot.loki.appender.cfg @@ -0,0 +1,41 @@ +################################################################################ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +################################################################################ +#Server Parameters +#loki.url: Loki server IP address and port +#loki.username: User configured on the Loki server +#loki.password: Password configured on the Loki server + +################################################################################ +#loki.url=http://127.0.0.1:3100/loki/api/v1/push + +# Autenticación (opcional) +#loki.username=loki +#loki.password=loki + +# # Topics permitidos (separados por coma). Topicos generales: merlot/*, phoebus/*, iotdb/*, decanter/* +#loki.topics=decanter/collect/log,decanter/collect/metric,phoebus/data/test,merlot/archiver/test + +# Labels estáticas (siempre se añaden) +#loki.label.job=merlot +#loki.label.env=dev +#loki.label.app=plc4x-archiver + +# Labels con valores por defecto (pueden ser sobrescritos por el evento) +#loki.label.logLevel=INFO +#loki.label.component=archiver diff --git a/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/main/java/org/apache/plc4x/merlot/archiver/impl/MerlotLokiAppender.java b/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/main/java/org/apache/plc4x/merlot/archiver/impl/MerlotLokiAppender.java new file mode 100644 index 00000000..7d247146 --- /dev/null +++ b/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/main/java/org/apache/plc4x/merlot/archiver/impl/MerlotLokiAppender.java @@ -0,0 +1,178 @@ +package org.apache.plc4x.merlot.archiver.impl; + +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.time.Duration; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.nio.charset.StandardCharsets; + +import org.osgi.service.cm.ConfigurationException; +import org.osgi.service.cm.ManagedService; +import org.osgi.service.event.Event; +import org.osgi.service.event.EventHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class MerlotLokiAppender implements EventHandler, ManagedService { + + private static final Logger LOGGER = LoggerFactory.getLogger(MerlotLokiAppender.class); + + private String url; + private String username; + private String password; + private final Set allowedTopics = new HashSet<>(); + private final Map labels = new HashMap<>(); + + private HttpClient httpClient; + + public MerlotLokiAppender() { + } + + public void init() { + LOGGER.info("Starting the Merlot-Loki appender"); + httpClient = HttpClient.newBuilder() + .connectTimeout(Duration.ofSeconds(5)) + .build(); + } + + public void destroy() { + LOGGER.info("Deleting the Merlot-Loki appender module"); + httpClient.close(); + httpClient.shutdownNow(); + } + + //Inject HttpClient for use with Mockito + public void setHttpClient(HttpClient httpClient) { + this.httpClient = httpClient; + } + + public void setUrl(String url) { + this.url = url; + } + + @Override + public void handleEvent(Event event) { + String topic = event.getTopic(); + + //The topic must match those listed in the “loki.topics” property of the corresponding cfg file + if (!allowedTopics.isEmpty() && !allowedTopics.contains(topic)) { + return; + } + //For events without loki.label. tags, general tags are assigned as the primary tags (cfg file) + Map eventLabels = new HashMap<>(this.labels); + + StringBuilder msgBuilder = new StringBuilder(); + msgBuilder.append("[").append(topic).append("] "); + + for (String prop : event.getPropertyNames()) { + Object value = event.getProperty(prop); + + //Static tags will be sent as message content to Loki. + if (prop.startsWith("loki.label.")) { + String labelName = prop.substring("loki.label.".length()); + eventLabels.put(labelName, value.toString()); + } else if (!prop.equals("event.topics") && !prop.equals("service.id") && !prop.equals("subject")) { + msgBuilder.append(prop).append("=").append(value).append(" "); + } + } + + sendLokiServer(msgBuilder.toString().trim(), eventLabels); + } + + public void sendLokiServer(String message, Map dynamicLabels) { + if (this.url == null || this.url.isEmpty()) { + return; + } + + try { + long timeNano = System.currentTimeMillis() * 1_000_000; + + //Label classifier + StringBuilder labelsJson = new StringBuilder("{"); + + StringJoiner sj = new StringJoiner(","); + + dynamicLabels.forEach((k, v) -> { + sj.add("\"" + escapeJson(k) + "\":\"" + escapeJson(v) + "\""); + }); + + labelsJson.append(sj.toString()).append("}"); + + //Payload to be sent to the Loki server, with the tags from the event as well as those saved in the cfg file. + String payload = "{\"streams\": [{\"stream\": " + labelsJson + ", \"values\": [ [\"" + timeNano + "\", \"" + escapeJson(message) + "\"] ]}]}"; + + //The message must be sent as JSON + HttpRequest.Builder requestBuilder = HttpRequest.newBuilder() + .uri(URI.create(this.url)) + .header("Content-Type", "application/json") + .POST(HttpRequest.BodyPublishers.ofString(payload, StandardCharsets.UTF_8)); + + //If the server requires authentication, it must be encrypted + if (this.username != null && this.password != null) { + String auth = this.username + ":" + this.password; + String encoded = Base64.getEncoder().encodeToString(auth.getBytes()); + requestBuilder.header("Authorization", "Basic " + encoded); + } + + //Send the request asynchronously to avoid blocking the Karaf internal bus + httpClient.sendAsync(requestBuilder.build(), HttpResponse.BodyHandlers.ofString()) + .thenAccept(response -> { + if (response.statusCode() != 204 && response.statusCode() != 200) { + LOGGER.error("Loki rejected (Code {} ): {}", response.statusCode(), response.body()); + } + }) + .exceptionally(e -> { + LOGGER.error("Loki Connection Error: {}", e.getMessage()); + return null; + }); + + } catch (Exception e) { + LOGGER.error("Critical Error in MerlotLokiAppender: {}", e.getMessage()); + } + } + + private String escapeJson(String s) { + if (s == null) { + return ""; + } + //Escape character correction + return s.replace("\\", "\\\\") + .replace("\"", "\\\"") + .replace("\n", "\\n") + .replace("\r", "") + .replace("\t", "\\t"); + } + + @Override + public void updated(Dictionary properties) throws ConfigurationException { + if (properties == null || properties.isEmpty()) { + return; + } + + //Connection parameters + this.url = (String) properties.get("loki.url"); + this.username = (String) properties.get("loki.username"); + this.password = (String) properties.get("loki.password"); + + // Topic configuration + this.allowedTopics.clear(); + String strTopics = (String) properties.get("loki.topics"); + if (strTopics != null) { + Arrays.stream(strTopics.split(",")).map(String::trim).forEach(this.allowedTopics::add); + } + + // Configuration of dynamic, static labels + this.labels.clear(); + Enumeration keys = properties.keys(); + while (keys.hasMoreElements()) { + String key = keys.nextElement(); + if (key.startsWith("loki.label.")) { + String labelName = key.substring("loki.label.".length()); + this.labels.put(labelName, properties.get(key).toString()); + } + } + } +} diff --git a/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/main/resources/OSGI-INF/blueprint/archiver-service.xml b/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/main/resources/OSGI-INF/blueprint/archiver-service.xml index d25c314b..4e1e90a2 100644 --- a/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/main/resources/OSGI-INF/blueprint/archiver-service.xml +++ b/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/main/resources/OSGI-INF/blueprint/archiver-service.xml @@ -30,7 +30,11 @@ - + + - + + + + + + - + mvn:org.apache.plc4x.merlot.archiver/org.apache.plc4x.merlot.archiver/${project.version}/cfg7 mvn:org.apache.plc4x.merlot.archiver/org.apache.plc4x.merlot.archiver/${project.version}/cfg3 mvn:org.apache.plc4x.merlot.archiver/org.apache.plc4x.merlot.archiver/${project.version}/cfg3 diff --git a/plc4j/tools/merlot/org.apache.plc4x.merlot.kafka/pom.xml b/plc4j/tools/merlot/org.apache.plc4x.merlot.kafka/pom.xml index c42666e6..8d541b81 100644 --- a/plc4j/tools/merlot/org.apache.plc4x.merlot.kafka/pom.xml +++ b/plc4j/tools/merlot/org.apache.plc4x.merlot.kafka/pom.xml @@ -142,6 +142,7 @@ org.apache.kafka kafka-clients ${kafka.version} + com.fasterxml.jackson.core diff --git a/plc4j/tools/merlot/pom.xml b/plc4j/tools/merlot/pom.xml index c101b64e..3e333ea1 100644 --- a/plc4j/tools/merlot/pom.xml +++ b/plc4j/tools/merlot/pom.xml @@ -100,6 +100,7 @@ under the License. 4.0.0 3.5.3 + 3.9.2 7.0.9 1.0.7 From f244a691ca769fea989d9728c617295ee631447c Mon Sep 17 00:00:00 2001 From: Lerb123 Date: Mon, 11 May 2026 11:53:51 -0400 Subject: [PATCH 2/6] fix: Implement Loki appender for Karaf event bus, added comments. --- .../org.apache.plc4x.merlot.loki.appender.cfg | 8 +++----- .../archiver/impl/MerlotLokiAppender.java | 19 ++++++++++++++++++- .../archiver/test/MerlotLokiAppenderTest.java | 1 + 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/main/cfg/org.apache.plc4x.merlot.loki.appender.cfg b/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/main/cfg/org.apache.plc4x.merlot.loki.appender.cfg index 2aa13fe3..2ca9a72c 100644 --- a/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/main/cfg/org.apache.plc4x.merlot.loki.appender.cfg +++ b/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/main/cfg/org.apache.plc4x.merlot.loki.appender.cfg @@ -24,18 +24,16 @@ ################################################################################ #loki.url=http://127.0.0.1:3100/loki/api/v1/push -# Autenticación (opcional) +# Authentication (optional) #loki.username=loki #loki.password=loki -# # Topics permitidos (separados por coma). Topicos generales: merlot/*, phoebus/*, iotdb/*, decanter/* +#Allowed topics (separated by commas). General topics: merlot/*, phoebus/*, iotdb/*, decanter/* #loki.topics=decanter/collect/log,decanter/collect/metric,phoebus/data/test,merlot/archiver/test -# Labels estáticas (siempre se añaden) +# Static labels (always added) #loki.label.job=merlot #loki.label.env=dev #loki.label.app=plc4x-archiver - -# Labels con valores por defecto (pueden ser sobrescritos por el evento) #loki.label.logLevel=INFO #loki.label.component=archiver diff --git a/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/main/java/org/apache/plc4x/merlot/archiver/impl/MerlotLokiAppender.java b/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/main/java/org/apache/plc4x/merlot/archiver/impl/MerlotLokiAppender.java index 7d247146..4ccf4100 100644 --- a/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/main/java/org/apache/plc4x/merlot/archiver/impl/MerlotLokiAppender.java +++ b/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/main/java/org/apache/plc4x/merlot/archiver/impl/MerlotLokiAppender.java @@ -1,3 +1,19 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.apache.plc4x.merlot.archiver.impl; import java.net.URI; @@ -44,11 +60,12 @@ public void destroy() { httpClient.shutdownNow(); } - //Inject HttpClient for use with Mockito + //Inject HttpClient for use with WireMock public void setHttpClient(HttpClient httpClient) { this.httpClient = httpClient; } + ////Inject Url for use with WireMock public void setUrl(String url) { this.url = url; } diff --git a/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/test/java/org/apache/plc4x/merlot/archiver/test/MerlotLokiAppenderTest.java b/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/test/java/org/apache/plc4x/merlot/archiver/test/MerlotLokiAppenderTest.java index 22164187..6835e742 100644 --- a/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/test/java/org/apache/plc4x/merlot/archiver/test/MerlotLokiAppenderTest.java +++ b/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/test/java/org/apache/plc4x/merlot/archiver/test/MerlotLokiAppenderTest.java @@ -49,6 +49,7 @@ public void setUp() { @Test public void pushLogToLoki() { + //Stub for POST requests to the URL /loki/api/v1/push wireMockServer.stubFor(WireMock.post(urlEqualTo("/loki/api/v1/push")) .willReturn(aResponse() .withStatus(204) From 45d0bc47d65a863fa5f898beb671bec8444275bd Mon Sep 17 00:00:00 2001 From: Lerb123 Date: Thu, 14 May 2026 13:41:21 -0400 Subject: [PATCH 3/6] feat: Functional test for Loki Appender using WireMock --- plc4j/tools/merlot/anahata.md | 3 --- plc4j/tools/merlot/merlot.iml | 15 --------------- .../org.apache.plc4x.merlot.archiver.iml | 8 ++++++++ .../src/main/feature/feature.xml | 8 ++++++++ .../merlot/org.apache.plc4x.merlot.kafka/pom.xml | 1 - .../tools/merlot/org.apache.plc4x.merlot/pom.xml | 3 +-- 6 files changed, 17 insertions(+), 21 deletions(-) delete mode 100644 plc4j/tools/merlot/anahata.md delete mode 100644 plc4j/tools/merlot/merlot.iml create mode 100644 plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/org.apache.plc4x.merlot.archiver.iml diff --git a/plc4j/tools/merlot/anahata.md b/plc4j/tools/merlot/anahata.md deleted file mode 100644 index 7a959db9..00000000 --- a/plc4j/tools/merlot/anahata.md +++ /dev/null @@ -1,3 +0,0 @@ -# Anahata Project Notes - -This file is for Anahata AI Assistant's notes regarding the 'merlot' project. diff --git a/plc4j/tools/merlot/merlot.iml b/plc4j/tools/merlot/merlot.iml deleted file mode 100644 index 452f2108..00000000 --- a/plc4j/tools/merlot/merlot.iml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/org.apache.plc4x.merlot.archiver.iml b/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/org.apache.plc4x.merlot.archiver.iml new file mode 100644 index 00000000..359c4696 --- /dev/null +++ b/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/org.apache.plc4x.merlot.archiver.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/plc4j/tools/merlot/org.apache.plc4x.merlot.features/src/main/feature/feature.xml b/plc4j/tools/merlot/org.apache.plc4x.merlot.features/src/main/feature/feature.xml index c1368902..a78fd7d7 100755 --- a/plc4j/tools/merlot/org.apache.plc4x.merlot.features/src/main/feature/feature.xml +++ b/plc4j/tools/merlot/org.apache.plc4x.merlot.features/src/main/feature/feature.xml @@ -36,6 +36,7 @@ pax-web-karaf plc4x-epics-gpclient + plc4x-kafka wrap:mvn:org.osgi/org.osgi.service.device/1.1.0/$Export-Package=*;version="1.1.0",!* @@ -728,6 +729,13 @@ mvn:org.apache.activemq/artemis-features/2.30.0 + + wrap:mvn:org.apache.kafka/kafka-clients/${kafka.version}/$Bundle-SymbolicName=kafka-client&Bundle-Version=${kafka.version}&Bundle-ManifestVersion="2"&Export-Package=*;version="${kafka.version}",!* + wrap:mvn:org.apache.karaf.decanter.collector/org.apache.karaf.decanter.collector.utils/2.12.0/$Bundle-SymbolicName=decanter-collector-utils&Bundle-Version=2.12.0&Bundle-ManifestVersion="2"&Export-Package=*;version="2.12.0",!* + mvn:org.apache.plc4x.merlot.kafka/org.apache.plc4x.merlot.kafka/${project.version} + mvn:org.apache.plc4x.merlot.kafka/org.apache.plc4x.merlot.kafka/${project.version}/cfg + + wrap:mvn:org.apache.iotdb/iotdb-session/${iotdb.session.version}/$Bundle-SymbolicName=iotdb-session&Bundle-Version=${iotdb.session.version}&Bundle-ManifestVersion="2"&Export-Package=*;version="${iotdb.session.version}",!* diff --git a/plc4j/tools/merlot/org.apache.plc4x.merlot.kafka/pom.xml b/plc4j/tools/merlot/org.apache.plc4x.merlot.kafka/pom.xml index 8d541b81..c42666e6 100644 --- a/plc4j/tools/merlot/org.apache.plc4x.merlot.kafka/pom.xml +++ b/plc4j/tools/merlot/org.apache.plc4x.merlot.kafka/pom.xml @@ -142,7 +142,6 @@ org.apache.kafka kafka-clients ${kafka.version} - com.fasterxml.jackson.core diff --git a/plc4j/tools/merlot/org.apache.plc4x.merlot/pom.xml b/plc4j/tools/merlot/org.apache.plc4x.merlot/pom.xml index 96779637..d042bb55 100644 --- a/plc4j/tools/merlot/org.apache.plc4x.merlot/pom.xml +++ b/plc4j/tools/merlot/org.apache.plc4x.merlot/pom.xml @@ -201,8 +201,7 @@ - org.apache.plc4x.merlot.features - decanter-appender-loki + org.apache.plc4x.merlot.features wrap classpath shell From 69c703711a0a6fc289baff4a04d538ed70b0cbd7 Mon Sep 17 00:00:00 2001 From: Lerb123 Date: Thu, 14 May 2026 16:04:03 -0400 Subject: [PATCH 4/6] feat: CI Pipeline for MerlotLokiAppender --- .../org.apache.plc4x.merlot.archiver/pom.xml | 65 +++++++++++++--- .../archiver/test/MerlotLokiAppenderTest.java | 76 ------------------- .../runner/MerlotLokiAppenderRunnerTest.java | 16 ++++ .../LokiAppenderDefinition.java | 70 +++++++++++++++++ .../src/test/resources/features/loki.feature | 6 ++ 5 files changed, 147 insertions(+), 86 deletions(-) delete mode 100644 plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/test/java/org/apache/plc4x/merlot/archiver/test/MerlotLokiAppenderTest.java create mode 100644 plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/test/java/runner/MerlotLokiAppenderRunnerTest.java create mode 100644 plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/test/java/stepdefinition/LokiAppenderDefinition.java create mode 100644 plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/test/resources/features/loki.feature diff --git a/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/pom.xml b/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/pom.xml index 8e71af28..5edea7a2 100644 --- a/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/pom.xml +++ b/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/pom.xml @@ -34,6 +34,19 @@ PLC4J: Merlot :: archiver :: Historical archive decanter OSGi blueprint bundle project. + + + 1.18.46 + 4.13.2 + 6.0.3 + 5.23.0 + 3.13.2 + 1.1.0 + 6.0.3 + 7.34.3 + 7.34.3 + + @@ -62,8 +75,8 @@ org.apache.maven.plugins maven-compiler-plugin - 17 - 17 + 21 + 21 256M @@ -227,19 +240,19 @@ org.junit.jupiter junit-jupiter-api - 5.10.3 + ${junit-jupiter.version} test org.junit.jupiter junit-jupiter-params - 5.10.3 + ${junit-jupiter.version} test org.junit.jupiter junit-jupiter-engine - 5.10.3 + ${junit-jupiter.version} test @@ -266,14 +279,14 @@ junit junit - 4.13.2 + ${junit.version} test jar org.projectlombok lombok - 1.18.42 + ${lombok.version} jar @@ -285,22 +298,54 @@ org.mockito mockito-junit-jupiter - 5.5.0 + ${mockito-junit-jupiter.version} test org.wiremock wiremock - 3.13.1 + ${wiremock.version} test de.mkammerer.wiremock-junit5 wiremock-junit5 - 1.1.0 + ${wiremock-junit5.version} test jar + + + org.junit.platform + junit-platform-launcher + ${junit-platform.version} + test + + + + org.junit.platform + junit-platform-suite-api + ${junit-platform.version} + test + + + + io.cucumber + cucumber-java + ${cucumber-java.version} + + + + io.cucumber + cucumber-junit-platform-engine + ${cucumber-junit-platform-engine.version} + test + + + org.junit.platform + junit-platform-suite-engine + ${junit-platform.version} test + diff --git a/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/test/java/org/apache/plc4x/merlot/archiver/test/MerlotLokiAppenderTest.java b/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/test/java/org/apache/plc4x/merlot/archiver/test/MerlotLokiAppenderTest.java deleted file mode 100644 index 6835e742..00000000 --- a/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/test/java/org/apache/plc4x/merlot/archiver/test/MerlotLokiAppenderTest.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.plc4x.merlot.archiver.test; - -import com.github.tomakehurst.wiremock.WireMockServer; -import static com.github.tomakehurst.wiremock.client.WireMock.*; -import com.github.tomakehurst.wiremock.client.WireMock; -import java.net.http.HttpClient; -import java.util.Map; -import org.apache.plc4x.merlot.archiver.impl.MerlotLokiAppender; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -public class MerlotLokiAppenderTest { - - private MerlotLokiAppender mLoki; - private WireMockServer wireMockServer; - private HttpClient httpClient; - private String lokiUrl = "http://localhost:3100/loki/api/v1/push"; - - @BeforeEach - public void setUp() { - - mLoki = new MerlotLokiAppender(); - httpClient = HttpClient.newHttpClient(); - mLoki.setHttpClient(httpClient); - mLoki.setUrl(lokiUrl); - - wireMockServer = new WireMockServer(3100); - wireMockServer.start(); - WireMock.configureFor("localhost", 3100); - } - - @Test - public void pushLogToLoki() { - - //Stub for POST requests to the URL /loki/api/v1/push - wireMockServer.stubFor(WireMock.post(urlEqualTo("/loki/api/v1/push")) - .willReturn(aResponse() - .withStatus(204) - .withBody("Successfully pushed"))); - - //Labels - Map labels = Map.of("job", "test", "env", "dev"); - - //Send data to the simulated “Loki Server” - mLoki.sendLokiServer("Test Message", labels); - - // Verify that at least one HTTP request was received during the test - verify(postRequestedFor(urlEqualTo("/loki/api/v1/push")) - .withHeader("Content-Type", matching("application/json.*")) - .withRequestBody(containing("Test Message")) - .withRequestBody(containing("\"job\":\"test\""))); - } - - @AfterEach - void tearDown() { - //Stop server - wireMockServer.stop(); - } -} diff --git a/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/test/java/runner/MerlotLokiAppenderRunnerTest.java b/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/test/java/runner/MerlotLokiAppenderRunnerTest.java new file mode 100644 index 00000000..6c610e50 --- /dev/null +++ b/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/test/java/runner/MerlotLokiAppenderRunnerTest.java @@ -0,0 +1,16 @@ +package runner; + +import org.junit.platform.suite.api.ConfigurationParameter; +import org.junit.platform.suite.api.IncludeEngines; +import org.junit.platform.suite.api.SelectClasspathResource; +import org.junit.platform.suite.api.Suite; + +@Suite +@IncludeEngines("cucumber") +@SelectClasspathResource("features") +@ConfigurationParameter(key = "cucumber.glue", value = "stepdefinition") +@ConfigurationParameter(key = "cucumber.snippet-type", value = "camelcase") +public class MerlotLokiAppenderRunnerTest { +} + + diff --git a/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/test/java/stepdefinition/LokiAppenderDefinition.java b/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/test/java/stepdefinition/LokiAppenderDefinition.java new file mode 100644 index 00000000..949d0971 --- /dev/null +++ b/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/test/java/stepdefinition/LokiAppenderDefinition.java @@ -0,0 +1,70 @@ +package stepdefinition; + +import com.github.tomakehurst.wiremock.WireMockServer; +import com.github.tomakehurst.wiremock.client.WireMock; +import io.cucumber.java.en.Given; +import io.cucumber.java.en.Then; +import io.cucumber.java.en.When; +import org.apache.plc4x.merlot.archiver.impl.MerlotLokiAppender; +import org.apache.plc4x.merlot.archiver.impl.MerlotPvRtCollectorImpl; +import org.slf4j.LoggerFactory; + +import java.net.http.HttpClient; +import java.util.Map; + +import static com.github.tomakehurst.wiremock.client.WireMock.*; +import static com.github.tomakehurst.wiremock.client.WireMock.containing; +import static com.github.tomakehurst.wiremock.client.WireMock.matching; +import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor; + +public class LokiAppenderDefinition { + private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(LokiAppenderDefinition.class); + + private final MerlotLokiAppender mLoki = new MerlotLokiAppender(); + private final WireMockServer wireMockServer = new WireMockServer(3100); + private final HttpClient httpClient = HttpClient.newHttpClient(); + + private Map labels; + + + @Given("Labels supplied for the message {string}, {string}, {string}, {string}") + public void labelsSuppliedForTheMessage(String label1, String label2, String label3, String label4) { + mLoki.setHttpClient(httpClient); + LOGGER.info("Labels: {} {} {} {}", label1, label2, label3, label4); + //Labels + labels = Map.of(label1, label2, label3, label4); + + } + @Given("Url Loki Server {string}") + public void url(String url) { + mLoki.setUrl(url); + wireMockServer.start(); + WireMock.configureFor("localhost", 3100); + } + + @When("The server returned an HTTP {int} response") + public void theServerReturnedAnHTTPResponse(Integer code) { + //Stub for POST requests to the URL /loki/api/v1/push + wireMockServer.stubFor(WireMock.post(urlEqualTo("/loki/api/v1/push")) + .willReturn(aResponse() + .withStatus(code) + .withBody("Successfully pushed"))); + //Send data to the simulated “Loki Server” + mLoki.sendLokiServer("Test Message", labels); + + // Verify that at least one HTTP request was received during the test + verify(postRequestedFor(urlEqualTo("/loki/api/v1/push")) + .withHeader("Content-Type", matching("application/json.*")) + .withRequestBody(containing("Test Message")) + .withRequestBody(containing("\"job\":\"test\""))); + + + } + @Then("The instance displays “Log sent”") + public void theInstanceDisplaysLogSent() { + //Stop server + wireMockServer.stop(); + LOGGER.info("Successfully pushed"); + } + +} diff --git a/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/test/resources/features/loki.feature b/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/test/resources/features/loki.feature new file mode 100644 index 00000000..4f828ab6 --- /dev/null +++ b/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/test/resources/features/loki.feature @@ -0,0 +1,6 @@ +Feature: Sending data to the Loki server + Scenario: Build Message + Given Labels supplied for the message "job", "test", "env", "dev" + And Url Loki Server "http://localhost:3100/loki/api/v1/push" + When The server returned an HTTP 204 response + Then The instance displays “Log sent” \ No newline at end of file From 260b2d73d732b18f8a2a04041dd387ae4e273707 Mon Sep 17 00:00:00 2001 From: Lerb123 Date: Thu, 14 May 2026 16:49:32 -0400 Subject: [PATCH 5/6] Correction to the Maven configuration to prevent tests from being skipped; add .mvn --- plc4j/tools/merlot/.mvn/maven.config | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 plc4j/tools/merlot/.mvn/maven.config diff --git a/plc4j/tools/merlot/.mvn/maven.config b/plc4j/tools/merlot/.mvn/maven.config new file mode 100644 index 00000000..8c834544 --- /dev/null +++ b/plc4j/tools/merlot/.mvn/maven.config @@ -0,0 +1,3 @@ +-DskipTests=false +-Dgradle.cache.local.enabled=false +-Dforce.tests=true \ No newline at end of file From 0a830ee46683959dfe310092a736fbd289c802cd Mon Sep 17 00:00:00 2001 From: Lerb123 Date: Thu, 14 May 2026 16:55:07 -0400 Subject: [PATCH 6/6] Correction to Maven configuration: local cache is disabled --- plc4j/tools/merlot/.mvn/maven.config | 2 -- 1 file changed, 2 deletions(-) diff --git a/plc4j/tools/merlot/.mvn/maven.config b/plc4j/tools/merlot/.mvn/maven.config index 8c834544..50431ccf 100644 --- a/plc4j/tools/merlot/.mvn/maven.config +++ b/plc4j/tools/merlot/.mvn/maven.config @@ -1,3 +1 @@ --DskipTests=false -Dgradle.cache.local.enabled=false --Dforce.tests=true \ No newline at end of file