diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..92322c4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.idea/ +target/ diff --git a/README.adoc b/README.adoc index 0f563cc..e102f52 100644 --- a/README.adoc +++ b/README.adoc @@ -1,35 +1,34 @@ -// Before publishing your new repository: -// 1. Write the readme file -// 2. Update the issues link in Contributing section in the readme file -// 3. Update the discussion link in config.yml file in .github/ISSUE_TEMPLATE directory += RELP Commit Latency Probe rlp_11 -= repo-template - -// Add a short description of your project. Tell what your project does and what it's used for. - -This is a template repository for Teragrep organization. +Measures latency for RELP events. == Features -// List your project's features +Provides Dropwizard metrics -== Documentation +Provides Prometheus endpoint -See the official documentation on https://docs.teragrep.com[docs.teragrep.com]. +== Documentation == Limitations -// If your project has limitations, please list them. Otherwise remove this section. +== How to compile -== How to [compile/use/implement] +[source] +---- +mvn clean package +---- -// add instructions how people can start to use your project +== How to use -== Contributing +[source] +---- +java -jar rlp_11.jar +---- -// Change the repository name in the issues link to match with your project's name +== Contributing -You can involve yourself with our project by https://github.com/teragrep/repo-template/issues/new/choose[opening an issue] or submitting a pull request. +You can involve yourself with our project by https://github.com/teragrep/rlp_11/issues/new/choose[opening an issue] or submitting a pull request. Contribution requirements: diff --git a/eclipse-java-formatter.xml b/eclipse-java-formatter.xml new file mode 100644 index 0000000..53b9f2a --- /dev/null +++ b/eclipse-java-formatter.xml @@ -0,0 +1,450 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/license-header b/license-header new file mode 100644 index 0000000..1ace12e --- /dev/null +++ b/license-header @@ -0,0 +1,45 @@ +/* + * RELP Commit Latency Probe RLP-11 + * Copyright (C) 2024 Suomen Kanuuna Oy + * + * 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 . + * + * + * Additional permission under GNU Affero General Public License version 3 + * section 7 + * + * If you modify this Program, or any covered work, by linking or combining it + * with other code, such other code is not for that reason alone subject to any + * of the requirements of the GNU Affero GPL version 3 as long as this Program + * is the same Program as licensed from Suomen Kanuuna Oy without any additional + * modifications. + * + * Supplemented terms under GNU Affero General Public License version 3 + * section 7 + * + * Origin of the software must be attributed to Suomen Kanuuna Oy. Any modified + * versions must be marked as "Modified version of" The Program. + * + * Names of the licensors and authors may not be used for publicity purposes. + * + * No rights are granted for use of trade names, trademarks, or service marks + * which are in The Program if any. + * + * Licensee must indemnify licensors and authors for any liability that these + * contractual assumptions impose on licensors and authors. + * + * To the extent this program is licensed as part of the Commercial versions of + * Teragrep, the applicable Commercial License may apply to this file if you as + * a licensee so wish it. + */ diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..624dea0 --- /dev/null +++ b/pom.xml @@ -0,0 +1,623 @@ + + + 4.0.0 + com.teragrep + rlp_11 + ${revision}${sha1}${changelist} + jar + rlp_11 + RELP Commit Latency Probe + https://teragrep.com + + -SNAPSHOT + 0.0.1-SNAPSHOT + 4.2.28 + 11.0.24 + 1.1.7 + 2.1.3 + 17 + 1.11.3 + 5.11.3 + 2.24.1 + 17 + 17 + UTF-8 + UTF-8 + 0.16.0 + 0.0.1 + 1.0.1 + 4.0.3 + 8.0.1 + + 2.0.16 + + + + + com.teragrep + cnf_01 + ${cnf_01.version} + + + + com.teragrep + rlp_01 + ${rlp_01.version} + + + + com.teragrep + rlo_14 + ${rlo_14.version} + + + + io.dropwizard.metrics + metrics-core + ${dropwizard.metrics.version} + + + io.dropwizard.metrics + metrics-jmx + ${dropwizard.metrics.version} + + + + io.prometheus + simpleclient + ${prometheus.version} + + + io.prometheus + simpleclient_dropwizard + ${prometheus.version} + + + io.prometheus + simpleclient_servlet + ${prometheus.version} + + + io.prometheus + simpleclient_hotspot + ${prometheus.version} + + + + org.eclipse.jetty + jetty-servlet + ${eclipse.jetty.version} + + + + org.slf4j + slf4j-api + ${slf4j.version} + + + org.apache.logging.log4j + log4j-core + ${log4j2.version} + + + org.apache.logging.log4j + log4j-slf4j2-impl + ${log4j2.version} + + + + jakarta.json + jakarta.json-api + ${jakarta.json.version} + + + org.eclipse.parsson + parsson + ${eclipse.parsson.version} + + + + com.teragrep + rlp_03 + ${rlp_03.version} + test + + + + org.junit.jupiter + junit-jupiter-engine + ${junit.version} + test + + + org.junit.platform + junit-platform-launcher + ${junit.platform.version} + test + + + org.junit.jupiter + junit-jupiter-api + ${junit.version} + test + + + org.junit.jupiter + junit-jupiter-params + ${junit.version} + test + + + + ${project.basedir}/target + rlp_11 + + + true + src/main/resources + + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + 3.5.0 + + + + scan-errors + + check + + process-classes + + error + true + true + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scan-warnings + + check + + process-classes + + warning + true + false + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.apache.maven.plugins + maven-enforcer-plugin + 3.4.1 + + + enforce-settings + + enforce + + + + + + + junit:junit + + + + 3.6.53 + + + [17,18) + + + + + com.teragrep:*:0.0.1-SNAPSHOT + + + + All plugins are required to contain specific version. + org.apache.maven.plugins:maven-site-plugin,org.apache.maven.plugins:maven-resources-plugin,org.apache.maven.plugins:maven-clean-plugin,org.apache.maven.plugins:maven-install-plugin,org.apache.maven.plugins:maven-deploy-plugin,org.apache.maven.plugins:maven-compiler-plugin,org.apache.maven.plugins:maven-jar-plugin + + + Do not use any external repositories. + + + + + + + + + com.diffplug.spotless + spotless-maven-plugin + 2.43.0 + + + + ${project.basedir}/eclipse-java-formatter.xml + 4.10.0 + + + + ${project.basedir}/license-header + + + + + + UTF-8 + \n + true + false + 2 + recommended_2008_06 + true + true + true + + + + + + .gitattributes + .gitignore + + + + + true + 4 + + + + + + + + check + + compile + + + + + + org.apache.rat + apache-rat-plugin + 0.16.1 + false + + false + false + + + Teragrep + Affero General Public License v3 + + + + + + + Suomen Kanuuna Oy + 2024 + + RELP Commit Latency Probe RLP-11 + + Teragrep + + + true + false + + + .git/** + .gitattributes + .gitignore + .gitmodules + + .github/workflows/* + .github/ISSUE_TEMPLATE/* + .github/PULL_REQUEST_TEMPLATE/* + toolchains.xml + settings.xml + + pom.xml + eclipse-java-formatter.xml + src/main/assembly/jar-with-dependencies.xml + + src/test/resources/*.properties + + src/main/resources/log4j2.xml + + README.adoc + + + + + + check + + test + + + + + + org.apache.maven.plugins + maven-assembly-plugin + 3.7.1 + + + src/main/assembly/jar-with-dependencies.xml + + + + com.teragrep.rlp_11.Main + true + + + + + + make-assembly + + single + + package + + + + + org.apache.maven.plugins + maven-surefire-plugin + 3.5.2 + + all + true + + + + org.apache.maven.plugins + maven-failsafe-plugin + 3.5.2 + + + + integration-test + verify + + + + + + org.apache.maven.plugins + maven-deploy-plugin + 3.1.3 + + false + + + + + + + publish-github-packages + + + github + GitHub Packages + https://maven.pkg.github.com/teragrep/rlp_11 + + + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.6 + + + sign-artifacts + + sign + + verify + + + --pinentry-mode + loopback + + + + + + + + + + diff --git a/src/main/assembly/jar-with-dependencies.xml b/src/main/assembly/jar-with-dependencies.xml new file mode 100644 index 0000000..16d41cd --- /dev/null +++ b/src/main/assembly/jar-with-dependencies.xml @@ -0,0 +1,21 @@ + + jar-with-dependencies + + jar + + false + + + metaInf-services + + + + + true + true + runtime + + + diff --git a/src/main/java/com/teragrep/rlp_11/Configuration/ConfigurationException.java b/src/main/java/com/teragrep/rlp_11/Configuration/ConfigurationException.java new file mode 100644 index 0000000..69daa51 --- /dev/null +++ b/src/main/java/com/teragrep/rlp_11/Configuration/ConfigurationException.java @@ -0,0 +1,53 @@ +/* + * RELP Commit Latency Probe RLP-11 + * Copyright (C) 2024 Suomen Kanuuna Oy + * + * 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 . + * + * + * Additional permission under GNU Affero General Public License version 3 + * section 7 + * + * If you modify this Program, or any covered work, by linking or combining it + * with other code, such other code is not for that reason alone subject to any + * of the requirements of the GNU Affero GPL version 3 as long as this Program + * is the same Program as licensed from Suomen Kanuuna Oy without any additional + * modifications. + * + * Supplemented terms under GNU Affero General Public License version 3 + * section 7 + * + * Origin of the software must be attributed to Suomen Kanuuna Oy. Any modified + * versions must be marked as "Modified version of" The Program. + * + * Names of the licensors and authors may not be used for publicity purposes. + * + * No rights are granted for use of trade names, trademarks, or service marks + * which are in The Program if any. + * + * Licensee must indemnify licensors and authors for any liability that these + * contractual assumptions impose on licensors and authors. + * + * To the extent this program is licensed as part of the Commercial versions of + * Teragrep, the applicable Commercial License may apply to this file if you as + * a licensee so wish it. + */ +package com.teragrep.rlp_11.Configuration; + +public class ConfigurationException extends RuntimeException { + + public ConfigurationException(final String s) { + super(s); + } +} diff --git a/src/main/java/com/teragrep/rlp_11/Configuration/MetricsConfiguration.java b/src/main/java/com/teragrep/rlp_11/Configuration/MetricsConfiguration.java new file mode 100644 index 0000000..c096a1b --- /dev/null +++ b/src/main/java/com/teragrep/rlp_11/Configuration/MetricsConfiguration.java @@ -0,0 +1,91 @@ +/* + * RELP Commit Latency Probe RLP-11 + * Copyright (C) 2024 Suomen Kanuuna Oy + * + * 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 . + * + * + * Additional permission under GNU Affero General Public License version 3 + * section 7 + * + * If you modify this Program, or any covered work, by linking or combining it + * with other code, such other code is not for that reason alone subject to any + * of the requirements of the GNU Affero GPL version 3 as long as this Program + * is the same Program as licensed from Suomen Kanuuna Oy without any additional + * modifications. + * + * Supplemented terms under GNU Affero General Public License version 3 + * section 7 + * + * Origin of the software must be attributed to Suomen Kanuuna Oy. Any modified + * versions must be marked as "Modified version of" The Program. + * + * Names of the licensors and authors may not be used for publicity purposes. + * + * No rights are granted for use of trade names, trademarks, or service marks + * which are in The Program if any. + * + * Licensee must indemnify licensors and authors for any liability that these + * contractual assumptions impose on licensors and authors. + * + * To the extent this program is licensed as part of the Commercial versions of + * Teragrep, the applicable Commercial License may apply to this file if you as + * a licensee so wish it. + */ +package com.teragrep.rlp_11.Configuration; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Map; + +public class MetricsConfiguration { + + private static final Logger LOGGER = LoggerFactory.getLogger(MetricsConfiguration.class); + private final Map config; + + public MetricsConfiguration(final Map config) { + this.config = config; + } + + public String name() { + final String name = config.get("metrics.name"); + if (name == null) { + LOGGER.error("Configuration failure: is null"); + throw new ConfigurationException("Invalid value for received"); + } + return name; + } + + public int window() { + final String windowString = config.get("metrics.window"); + if (windowString == null) { + LOGGER.error("Configuration failure: is null"); + throw new ConfigurationException("Invalid value for received"); + } + final int window; + try { + window = Integer.parseInt(windowString); + } + catch (NumberFormatException e) { + LOGGER.error("Configuration failure: Invalid value for : <{}>", e.getMessage()); + throw e; + } + if (window <= 0) { + LOGGER.error("Configuration failure: <[{}]> too small, expected to be >0", window); + throw new ConfigurationException("Invalid value for received"); + } + return window; + } +} diff --git a/src/main/java/com/teragrep/rlp_11/Configuration/ProbeConfiguration.java b/src/main/java/com/teragrep/rlp_11/Configuration/ProbeConfiguration.java new file mode 100644 index 0000000..83315ec --- /dev/null +++ b/src/main/java/com/teragrep/rlp_11/Configuration/ProbeConfiguration.java @@ -0,0 +1,82 @@ +/* + * RELP Commit Latency Probe RLP-11 + * Copyright (C) 2024 Suomen Kanuuna Oy + * + * 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 . + * + * + * Additional permission under GNU Affero General Public License version 3 + * section 7 + * + * If you modify this Program, or any covered work, by linking or combining it + * with other code, such other code is not for that reason alone subject to any + * of the requirements of the GNU Affero GPL version 3 as long as this Program + * is the same Program as licensed from Suomen Kanuuna Oy without any additional + * modifications. + * + * Supplemented terms under GNU Affero General Public License version 3 + * section 7 + * + * Origin of the software must be attributed to Suomen Kanuuna Oy. Any modified + * versions must be marked as "Modified version of" The Program. + * + * Names of the licensors and authors may not be used for publicity purposes. + * + * No rights are granted for use of trade names, trademarks, or service marks + * which are in The Program if any. + * + * Licensee must indemnify licensors and authors for any liability that these + * contractual assumptions impose on licensors and authors. + * + * To the extent this program is licensed as part of the Commercial versions of + * Teragrep, the applicable Commercial License may apply to this file if you as + * a licensee so wish it. + */ +package com.teragrep.rlp_11.Configuration; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Map; + +public class ProbeConfiguration { + + private static final Logger LOGGER = LoggerFactory.getLogger(ProbeConfiguration.class); + private final Map config; + + public ProbeConfiguration(final Map config) { + this.config = config; + } + + public int interval() { + final String intervalString = config.get("probe.interval"); + if (intervalString == null) { + LOGGER.error("Configuration failure: is null"); + throw new ConfigurationException("Invalid value for received"); + } + final int interval; + try { + interval = Integer.parseInt(intervalString); + } + catch (NumberFormatException e) { + LOGGER.error("Configuration failure: Invalid value for : <{}>", e.getMessage()); + throw e; + } + if (interval <= 0) { + LOGGER.error("Configuration failure: <[{}]> too small, expected to be >0", interval); + throw new ConfigurationException("Invalid value for received"); + } + return interval; + } +} diff --git a/src/main/java/com/teragrep/rlp_11/Configuration/PrometheusConfiguration.java b/src/main/java/com/teragrep/rlp_11/Configuration/PrometheusConfiguration.java new file mode 100644 index 0000000..817b987 --- /dev/null +++ b/src/main/java/com/teragrep/rlp_11/Configuration/PrometheusConfiguration.java @@ -0,0 +1,86 @@ +/* + * RELP Commit Latency Probe RLP-11 + * Copyright (C) 2024 Suomen Kanuuna Oy + * + * 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 . + * + * + * Additional permission under GNU Affero General Public License version 3 + * section 7 + * + * If you modify this Program, or any covered work, by linking or combining it + * with other code, such other code is not for that reason alone subject to any + * of the requirements of the GNU Affero GPL version 3 as long as this Program + * is the same Program as licensed from Suomen Kanuuna Oy without any additional + * modifications. + * + * Supplemented terms under GNU Affero General Public License version 3 + * section 7 + * + * Origin of the software must be attributed to Suomen Kanuuna Oy. Any modified + * versions must be marked as "Modified version of" The Program. + * + * Names of the licensors and authors may not be used for publicity purposes. + * + * No rights are granted for use of trade names, trademarks, or service marks + * which are in The Program if any. + * + * Licensee must indemnify licensors and authors for any liability that these + * contractual assumptions impose on licensors and authors. + * + * To the extent this program is licensed as part of the Commercial versions of + * Teragrep, the applicable Commercial License may apply to this file if you as + * a licensee so wish it. + */ +package com.teragrep.rlp_11.Configuration; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Map; + +public class PrometheusConfiguration { + + private static final Logger LOGGER = LoggerFactory.getLogger(PrometheusConfiguration.class); + private final Map config; + + public PrometheusConfiguration(final Map config) { + this.config = config; + } + + public int port() { + final String portString = config.get("prometheus.port"); + if (portString == null) { + LOGGER.error("Configuration failure: is null"); + throw new ConfigurationException("Invalid value for received"); + } + final int port; + try { + port = Integer.parseInt(portString); + } + catch (NumberFormatException e) { + LOGGER.error("Configuration failure: Invalid value for : <{}>", e.getMessage()); + throw e; + } + if (port < 1 || port > 65535) { + LOGGER + .error( + "Configuration failure: <[{}]> is in invalid range, expected between 1 and 65535", + port + ); + throw new ConfigurationException("Invalid value for received"); + } + return port; + } +} diff --git a/src/main/java/com/teragrep/rlp_11/Configuration/RecordConfiguration.java b/src/main/java/com/teragrep/rlp_11/Configuration/RecordConfiguration.java new file mode 100644 index 0000000..9d3cfc6 --- /dev/null +++ b/src/main/java/com/teragrep/rlp_11/Configuration/RecordConfiguration.java @@ -0,0 +1,79 @@ +/* + * RELP Commit Latency Probe RLP-11 + * Copyright (C) 2024 Suomen Kanuuna Oy + * + * 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 . + * + * + * Additional permission under GNU Affero General Public License version 3 + * section 7 + * + * If you modify this Program, or any covered work, by linking or combining it + * with other code, such other code is not for that reason alone subject to any + * of the requirements of the GNU Affero GPL version 3 as long as this Program + * is the same Program as licensed from Suomen Kanuuna Oy without any additional + * modifications. + * + * Supplemented terms under GNU Affero General Public License version 3 + * section 7 + * + * Origin of the software must be attributed to Suomen Kanuuna Oy. Any modified + * versions must be marked as "Modified version of" The Program. + * + * Names of the licensors and authors may not be used for publicity purposes. + * + * No rights are granted for use of trade names, trademarks, or service marks + * which are in The Program if any. + * + * Licensee must indemnify licensors and authors for any liability that these + * contractual assumptions impose on licensors and authors. + * + * To the extent this program is licensed as part of the Commercial versions of + * Teragrep, the applicable Commercial License may apply to this file if you as + * a licensee so wish it. + */ +package com.teragrep.rlp_11.Configuration; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Map; + +public class RecordConfiguration { + + private static final Logger LOGGER = LoggerFactory.getLogger(RecordConfiguration.class); + private final Map config; + + public RecordConfiguration(final Map config) { + this.config = config; + } + + public String hostname() { + final String hostname = config.get("record.hostname"); + if (hostname == null) { + LOGGER.error("Configuration failure: is null"); + throw new ConfigurationException("Invalid value for received"); + } + return hostname; + } + + public String appname() { + final String appname = config.get("record.appname"); + if (appname == null) { + LOGGER.error("Configuration failure: is null"); + throw new ConfigurationException("Invalid value for received"); + } + return appname; + } +} diff --git a/src/main/java/com/teragrep/rlp_11/Configuration/TargetConfiguration.java b/src/main/java/com/teragrep/rlp_11/Configuration/TargetConfiguration.java new file mode 100644 index 0000000..ac2ee11 --- /dev/null +++ b/src/main/java/com/teragrep/rlp_11/Configuration/TargetConfiguration.java @@ -0,0 +1,120 @@ +/* + * RELP Commit Latency Probe RLP-11 + * Copyright (C) 2024 Suomen Kanuuna Oy + * + * 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 . + * + * + * Additional permission under GNU Affero General Public License version 3 + * section 7 + * + * If you modify this Program, or any covered work, by linking or combining it + * with other code, such other code is not for that reason alone subject to any + * of the requirements of the GNU Affero GPL version 3 as long as this Program + * is the same Program as licensed from Suomen Kanuuna Oy without any additional + * modifications. + * + * Supplemented terms under GNU Affero General Public License version 3 + * section 7 + * + * Origin of the software must be attributed to Suomen Kanuuna Oy. Any modified + * versions must be marked as "Modified version of" The Program. + * + * Names of the licensors and authors may not be used for publicity purposes. + * + * No rights are granted for use of trade names, trademarks, or service marks + * which are in The Program if any. + * + * Licensee must indemnify licensors and authors for any liability that these + * contractual assumptions impose on licensors and authors. + * + * To the extent this program is licensed as part of the Commercial versions of + * Teragrep, the applicable Commercial License may apply to this file if you as + * a licensee so wish it. + */ +package com.teragrep.rlp_11.Configuration; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Map; + +public class TargetConfiguration { + + private static final Logger LOGGER = LoggerFactory.getLogger(TargetConfiguration.class); + private final Map config; + + public TargetConfiguration(final Map config) { + this.config = config; + } + + public String hostname() { + final String hostname = config.get("target.hostname"); + if (hostname == null) { + LOGGER.error("Configuration failure: is null"); + throw new ConfigurationException("Invalid value for received"); + } + return hostname; + } + + public int port() { + final String portString = config.get("target.port"); + if (portString == null) { + LOGGER.error("Configuration failure: is null"); + throw new ConfigurationException("Invalid value for received"); + } + final int port; + try { + port = Integer.parseInt(portString); + } + catch (NumberFormatException e) { + LOGGER.error("Configuration failure: Invalid value for : <{}>", e.getMessage()); + throw e; + } + if (port < 1 || port > 65535) { + LOGGER + .error( + "Configuration failure: <[{}]> is in invalid range, expected between 1 and 65535", + port + ); + throw new ConfigurationException("Invalid value for received"); + } + return port; + } + + public int reconnectInterval() { + final String reconnectIntervalString = config.get("target.reconnectinterval"); + if (reconnectIntervalString == null) { + LOGGER.error("Configuration failure: is null"); + throw new ConfigurationException("Invalid value for received"); + } + final int reconnectInterval; + try { + reconnectInterval = Integer.parseInt(reconnectIntervalString); + } + catch (NumberFormatException e) { + LOGGER.error("Configuration failure: Invalid value for : <{}>", e.getMessage()); + throw e; + } + if (reconnectInterval <= 0) { + LOGGER + .error( + "Configuration failure: <[{}]> too small, expected to be >0", + reconnectInterval + ); + throw new ConfigurationException("Invalid value for received"); + } + return reconnectInterval; + } +} diff --git a/src/main/java/com/teragrep/rlp_11/Main.java b/src/main/java/com/teragrep/rlp_11/Main.java new file mode 100644 index 0000000..503e377 --- /dev/null +++ b/src/main/java/com/teragrep/rlp_11/Main.java @@ -0,0 +1,124 @@ +/* + * RELP Commit Latency Probe RLP-11 + * Copyright (C) 2024 Suomen Kanuuna Oy + * + * 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 . + * + * + * Additional permission under GNU Affero General Public License version 3 + * section 7 + * + * If you modify this Program, or any covered work, by linking or combining it + * with other code, such other code is not for that reason alone subject to any + * of the requirements of the GNU Affero GPL version 3 as long as this Program + * is the same Program as licensed from Suomen Kanuuna Oy without any additional + * modifications. + * + * Supplemented terms under GNU Affero General Public License version 3 + * section 7 + * + * Origin of the software must be attributed to Suomen Kanuuna Oy. Any modified + * versions must be marked as "Modified version of" The Program. + * + * Names of the licensors and authors may not be used for publicity purposes. + * + * No rights are granted for use of trade names, trademarks, or service marks + * which are in The Program if any. + * + * Licensee must indemnify licensors and authors for any liability that these + * contractual assumptions impose on licensors and authors. + * + * To the extent this program is licensed as part of the Commercial versions of + * Teragrep, the applicable Commercial License may apply to this file if you as + * a licensee so wish it. + */ +package com.teragrep.rlp_11; + +import com.teragrep.cnf_01.PathConfiguration; +import com.teragrep.rlp_11.Configuration.ProbeConfiguration; +import com.teragrep.rlp_11.Configuration.RecordConfiguration; +import com.teragrep.rlp_11.Configuration.MetricsConfiguration; +import com.teragrep.rlp_11.Configuration.PrometheusConfiguration; +import com.teragrep.rlp_11.Configuration.TargetConfiguration; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Map; + +public class Main { + + private static final Logger LOGGER = LoggerFactory.getLogger(Main.class); + + public static void main(final String[] args) throws com.teragrep.cnf_01.ConfigurationException { + final PathConfiguration pathConfiguration = new PathConfiguration( + System.getProperty("configurationPath", "etc/rlp_11.properties") + ); + final Map map; + try { + map = pathConfiguration.asMap(); + } + catch (com.teragrep.cnf_01.ConfigurationException e) { + LOGGER.error("Failed to create PathConfiguration: <{}>", e.getMessage()); + throw e; + } + final PrometheusConfiguration prometheusConfiguration = new PrometheusConfiguration(map); + final RecordConfiguration recordConfiguration = new RecordConfiguration(map); + final TargetConfiguration targetConfiguration = new TargetConfiguration(map); + final MetricsConfiguration metricsConfiguration = new MetricsConfiguration(map); + final RecordFactory recordFactory = new RecordFactory( + getHostname(), + recordConfiguration.hostname(), + recordConfiguration.appname() + ); + final ProbeConfiguration probeConfiguration = new ProbeConfiguration(map); + final RelpProbe relpProbe = new RelpProbe( + targetConfiguration, + probeConfiguration, + prometheusConfiguration, + metricsConfiguration, + recordFactory + ); + final Thread shutdownHook = new Thread(() -> { + LOGGER.debug("Stopping RelpProbe.."); + relpProbe.stop(); + LOGGER.debug("Shutting down."); + }); + Runtime.getRuntime().addShutdownHook(shutdownHook); + LOGGER + .info( + "Sending records to <[{}:{}]> every <[{}]> milliseconds", targetConfiguration.hostname(), + targetConfiguration.port(), probeConfiguration.interval() + ); + LOGGER + .info( + "Using hostname <[{}]> and appname <[{}]> for the records.", recordConfiguration.hostname(), + recordConfiguration.appname() + ); + relpProbe.start(); + } + + private static String getHostname() { + String origin; + try { + origin = InetAddress.getLocalHost().getHostName(); + } + catch (UnknownHostException e) { + origin = "localhost"; + LOGGER.warn("Could not get hostname, using <{}> instead", origin); + } + return origin; + } +} diff --git a/src/main/java/com/teragrep/rlp_11/RecordFactory.java b/src/main/java/com/teragrep/rlp_11/RecordFactory.java new file mode 100644 index 0000000..07cc514 --- /dev/null +++ b/src/main/java/com/teragrep/rlp_11/RecordFactory.java @@ -0,0 +1,87 @@ +/* + * RELP Commit Latency Probe RLP-11 + * Copyright (C) 2024 Suomen Kanuuna Oy + * + * 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 . + * + * + * Additional permission under GNU Affero General Public License version 3 + * section 7 + * + * If you modify this Program, or any covered work, by linking or combining it + * with other code, such other code is not for that reason alone subject to any + * of the requirements of the GNU Affero GPL version 3 as long as this Program + * is the same Program as licensed from Suomen Kanuuna Oy without any additional + * modifications. + * + * Supplemented terms under GNU Affero General Public License version 3 + * section 7 + * + * Origin of the software must be attributed to Suomen Kanuuna Oy. Any modified + * versions must be marked as "Modified version of" The Program. + * + * Names of the licensors and authors may not be used for publicity purposes. + * + * No rights are granted for use of trade names, trademarks, or service marks + * which are in The Program if any. + * + * Licensee must indemnify licensors and authors for any liability that these + * contractual assumptions impose on licensors and authors. + * + * To the extent this program is licensed as part of the Commercial versions of + * Teragrep, the applicable Commercial License may apply to this file if you as + * a licensee so wish it. + */ +package com.teragrep.rlp_11; + +import com.teragrep.rlo_14.Facility; +import com.teragrep.rlo_14.Severity; +import com.teragrep.rlo_14.SyslogMessage; +import jakarta.json.Json; +import jakarta.json.JsonObject; + +import java.nio.charset.StandardCharsets; +import java.time.Instant; + +public class RecordFactory { + + private final String origin; + private final String hostname; + private final String appname; + + public RecordFactory(final String origin, final String hostname, final String appname) { + this.origin = origin; + this.hostname = hostname; + this.appname = appname; + } + + public byte[] createRecord() { + final Instant timestamp = Instant.now(); + final String timestampString = timestamp.getEpochSecond() + "." + timestamp.getNano(); + final JsonObject event = Json + .createObjectBuilder() + .add("origin", origin) + .add("timestamp", timestampString) + .build(); + return new SyslogMessage() + .withTimestamp(timestamp.toEpochMilli()) + .withAppName(appname) + .withHostname(hostname) + .withFacility(Facility.USER) + .withSeverity(Severity.INFORMATIONAL) + .withMsg(event.toString()) + .toRfc5424SyslogMessage() + .getBytes(StandardCharsets.UTF_8); + } +} diff --git a/src/main/java/com/teragrep/rlp_11/RelpProbe.java b/src/main/java/com/teragrep/rlp_11/RelpProbe.java new file mode 100644 index 0000000..277138d --- /dev/null +++ b/src/main/java/com/teragrep/rlp_11/RelpProbe.java @@ -0,0 +1,252 @@ +/* + * RELP Commit Latency Probe RLP-11 + * Copyright (C) 2024 Suomen Kanuuna Oy + * + * 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 . + * + * + * Additional permission under GNU Affero General Public License version 3 + * section 7 + * + * If you modify this Program, or any covered work, by linking or combining it + * with other code, such other code is not for that reason alone subject to any + * of the requirements of the GNU Affero GPL version 3 as long as this Program + * is the same Program as licensed from Suomen Kanuuna Oy without any additional + * modifications. + * + * Supplemented terms under GNU Affero General Public License version 3 + * section 7 + * + * Origin of the software must be attributed to Suomen Kanuuna Oy. Any modified + * versions must be marked as "Modified version of" The Program. + * + * Names of the licensors and authors may not be used for publicity purposes. + * + * No rights are granted for use of trade names, trademarks, or service marks + * which are in The Program if any. + * + * Licensee must indemnify licensors and authors for any liability that these + * contractual assumptions impose on licensors and authors. + * + * To the extent this program is licensed as part of the Commercial versions of + * Teragrep, the applicable Commercial License may apply to this file if you as + * a licensee so wish it. + */ +package com.teragrep.rlp_11; + +import com.codahale.metrics.Counter; +import com.codahale.metrics.MetricRegistry; +import com.codahale.metrics.Slf4jReporter; +import com.codahale.metrics.SlidingWindowReservoir; +import com.codahale.metrics.Timer; +import com.codahale.metrics.jmx.JmxReporter; +import com.teragrep.rlp_01.RelpBatch; +import com.teragrep.rlp_01.RelpConnection; +import com.teragrep.rlp_11.Configuration.ProbeConfiguration; +import com.teragrep.rlp_11.Configuration.MetricsConfiguration; +import com.teragrep.rlp_11.Configuration.PrometheusConfiguration; +import com.teragrep.rlp_11.Configuration.TargetConfiguration; +import org.eclipse.jetty.server.Server; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.util.concurrent.CountDownLatch; + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicBoolean; + +import static com.codahale.metrics.MetricRegistry.name; + +public class RelpProbe { + + private static final Logger LOGGER = LoggerFactory.getLogger(RelpProbe.class); + private final TargetConfiguration targetConfiguration; + private final RecordFactory recordFactory; + private final PrometheusConfiguration prometheusConfiguration; + private final MetricsConfiguration metricsConfiguration; + private final ProbeConfiguration probeConfiguration; + private final AtomicBoolean stayRunning = new AtomicBoolean(true); + private RelpConnection relpConnection; + private final CountDownLatch latch = new CountDownLatch(1); + private boolean connected = false; + private Counter records; + private Counter resends; + private Counter connects; + private Counter disconnects; + private Counter retriedConnects; + private Timer sendLatency; + private Timer connectLatency; + private JmxReporter jmxReporter; + private Slf4jReporter slf4jReporter; + private Server jettyServer; + + public RelpProbe( + final TargetConfiguration targetConfiguration, + final ProbeConfiguration probeConfiguration, + final PrometheusConfiguration prometheusConfiguration, + final MetricsConfiguration metricsConfiguration, + final RecordFactory recordFactory + ) { + this.targetConfiguration = targetConfiguration; + this.probeConfiguration = probeConfiguration; + this.recordFactory = recordFactory; + this.prometheusConfiguration = prometheusConfiguration; + this.metricsConfiguration = metricsConfiguration; + } + + public void start() { + createMetrics(metricsConfiguration.name()); + this.jmxReporter.start(); + this.slf4jReporter.start(1, TimeUnit.MINUTES); + relpConnection = new RelpConnection(); + connect(); + while (stayRunning.get()) { + final RelpBatch relpBatch = new RelpBatch(); + relpBatch.insert(recordFactory.createRecord()); + + boolean allSent = false; + while (!allSent && stayRunning.get()) { + try (final Timer.Context context = sendLatency.time()) { + LOGGER.debug("Committing Relpbatch"); + relpConnection.commit(relpBatch); + records.inc(); + } + catch (IllegalStateException | IOException | java.util.concurrent.TimeoutException e) { + LOGGER.warn("Failed to commit: <{}>", e.getMessage()); + relpConnection.tearDown(); + connected = false; + } + LOGGER.debug("Verifying Transaction"); + allSent = relpBatch.verifyTransactionAll(); + if (!allSent) { + LOGGER.warn("Transactions failed, retrying"); + resends.inc(); + relpBatch.retryAllFailed(); + reconnect(); + } + } + try { + LOGGER.debug("Sleeping before sending next event"); + Thread.sleep(probeConfiguration.interval()); + } + catch (InterruptedException e) { + LOGGER.warn("Sleep interrupted: <{}>", e.getMessage()); + } + } + disconnect(); + latch.countDown(); + teardownMetrics(); + } + + private void connect() { + while (!connected && stayRunning.get()) { + try (final Timer.Context context = connectLatency.time()) { + LOGGER.debug("Connecting to <[{}:{}]>", targetConfiguration.hostname(), targetConfiguration.port()); + connected = relpConnection.connect(targetConfiguration.hostname(), targetConfiguration.port()); + LOGGER.debug("Connected."); + connects.inc(); + } + catch (TimeoutException | IOException e) { + LOGGER + .warn( + "Failed to connect to <[{}:{}]>: <{}>", targetConfiguration.hostname(), + targetConfiguration.port(), e.getMessage() + ); + } + if (!connected) { + try { + LOGGER.debug("Sleeping for <[{}]>ms before reconnecting", targetConfiguration.reconnectInterval()); + Thread.sleep(targetConfiguration.reconnectInterval()); + retriedConnects.inc(); + } + catch (InterruptedException e) { + LOGGER.warn("Sleep was interrupted: <{}>", e.getMessage()); + } + } + } + } + + private void reconnect() { + disconnect(); + connect(); + } + + private void disconnect() { + if (!connected) { + LOGGER.debug("No need to disconnect, not connected"); + return; + } + try { + LOGGER.debug("Disconnecting.."); + relpConnection.disconnect(); + disconnects.inc(); + } + catch (IOException | TimeoutException e) { + LOGGER.warn("Failed to disconnect: <{}>", e.getMessage()); + } + relpConnection.tearDown(); + LOGGER.debug("Disconnected."); + connected = false; + } + + public void stop() { + LOGGER.debug("Stop called"); + stayRunning.set(false); + try { + if (!latch.await(5L, TimeUnit.SECONDS)) { + LOGGER.error("Timed out while waiting for probe to shutdown."); + throw new RuntimeException("Timed out while waiting for probe to shutdown."); + } + } + catch (InterruptedException e) { + LOGGER.error("Interrupted while waiting for latch countdown"); + throw new RuntimeException(e); + } + LOGGER.debug("RelpProbe stopped."); + } + + private void createMetrics(final String name) { + final MetricRegistry metricRegistry = new MetricRegistry(); + this.records = metricRegistry.counter(name(RelpProbe.class, "<[" + name + "]>", "records")); + this.resends = metricRegistry.counter(name(RelpProbe.class, "<[" + name + "]>", "resends")); + this.connects = metricRegistry.counter(name(RelpProbe.class, "<[" + name + "]>", "connects")); + this.disconnects = metricRegistry.counter(name(RelpProbe.class, "<[" + name + "]>", "disconnects")); + this.retriedConnects = metricRegistry.counter(name(RelpProbe.class, "<[" + name + "]>", "retriedConnects")); + this.sendLatency = metricRegistry + .timer(name(RelpProbe.class, "<[" + name + "]>", "sendLatency"), () -> new Timer(new SlidingWindowReservoir(metricsConfiguration.window()))); + this.connectLatency = metricRegistry + .timer(name(RelpProbe.class, "<[" + name + "]>", "connectLatency"), () -> new Timer(new SlidingWindowReservoir(metricsConfiguration.window()))); + jmxReporter = JmxReporter.forRegistry(metricRegistry).build(); + slf4jReporter = Slf4jReporter + .forRegistry(metricRegistry) + .outputTo(LoggerFactory.getLogger(RelpProbe.class)) + .build(); + jettyServer = new Server(prometheusConfiguration.port()); + } + + private void teardownMetrics() { + jmxReporter.close(); + slf4jReporter.close(); + try { + jettyServer.stop(); + } + //CHECKSTYLE:OFF + catch (Exception e) { + throw new RuntimeException(e); + } + //CHECKSTYLE:ON + } +} diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml new file mode 100644 index 0000000..959d7dc --- /dev/null +++ b/src/main/resources/log4j2.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/java/com/teragrep/rlp_11/Configuration/MetricsConfigurationTest.java b/src/test/java/com/teragrep/rlp_11/Configuration/MetricsConfigurationTest.java new file mode 100644 index 0000000..aee9f41 --- /dev/null +++ b/src/test/java/com/teragrep/rlp_11/Configuration/MetricsConfigurationTest.java @@ -0,0 +1,110 @@ +/* + * RELP Commit Latency Probe RLP-11 + * Copyright (C) 2024 Suomen Kanuuna Oy + * + * 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 . + * + * + * Additional permission under GNU Affero General Public License version 3 + * section 7 + * + * If you modify this Program, or any covered work, by linking or combining it + * with other code, such other code is not for that reason alone subject to any + * of the requirements of the GNU Affero GPL version 3 as long as this Program + * is the same Program as licensed from Suomen Kanuuna Oy without any additional + * modifications. + * + * Supplemented terms under GNU Affero General Public License version 3 + * section 7 + * + * Origin of the software must be attributed to Suomen Kanuuna Oy. Any modified + * versions must be marked as "Modified version of" The Program. + * + * Names of the licensors and authors may not be used for publicity purposes. + * + * No rights are granted for use of trade names, trademarks, or service marks + * which are in The Program if any. + * + * Licensee must indemnify licensors and authors for any liability that these + * contractual assumptions impose on licensors and authors. + * + * To the extent this program is licensed as part of the Commercial versions of + * Teragrep, the applicable Commercial License may apply to this file if you as + * a licensee so wish it. + */ +package com.teragrep.rlp_11.Configuration; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.HashMap; +import java.util.Map; + +public class MetricsConfigurationTest { + + // metrics.name + @Test + public void testNonNullName() { + Map map = baseConfig(); + MetricsConfiguration metricsConfiguration = new MetricsConfiguration(map); + Assertions.assertEquals("target-name", metricsConfiguration.name()); + } + + @Test + public void testNullName() { + Map map = baseConfig(); + map.remove("metrics.name"); + MetricsConfiguration metricsConfiguration = new MetricsConfiguration(map); + Assertions.assertThrowsExactly(ConfigurationException.class, metricsConfiguration::name); + } + + // metrics.window + @Test + public void testGoodWindow() { + Map map = baseConfig(); + MetricsConfiguration metricsConfiguration = new MetricsConfiguration(map); + Assertions.assertEquals(1337, metricsConfiguration.window()); + } + + @Test + public void testNullWindow() { + Map map = baseConfig(); + map.remove("metrics.window"); + MetricsConfiguration metricsConfiguration = new MetricsConfiguration(map); + Assertions.assertThrowsExactly(ConfigurationException.class, metricsConfiguration::window); + } + + @Test + public void testTooSmallWindow() { + Map map = baseConfig(); + map.put("metrics.window", "0"); + MetricsConfiguration metricsConfiguration = new MetricsConfiguration(map); + Assertions.assertThrowsExactly(ConfigurationException.class, metricsConfiguration::window); + } + + @Test + public void testNonNumericWindow() { + Map map = baseConfig(); + map.put("metrics.window", "Not a number here"); + MetricsConfiguration metricsConfiguration = new MetricsConfiguration(map); + Assertions.assertThrowsExactly(NumberFormatException.class, metricsConfiguration::window); + } + + private Map baseConfig() { + Map map = new HashMap<>(); + map.put("metrics.name", "target-name"); + map.put("metrics.window", "1337"); + return map; + } +} diff --git a/src/test/java/com/teragrep/rlp_11/Configuration/ProbeConfigurationTest.java b/src/test/java/com/teragrep/rlp_11/Configuration/ProbeConfigurationTest.java new file mode 100644 index 0000000..b7b0276 --- /dev/null +++ b/src/test/java/com/teragrep/rlp_11/Configuration/ProbeConfigurationTest.java @@ -0,0 +1,93 @@ +/* + * RELP Commit Latency Probe RLP-11 + * Copyright (C) 2024 Suomen Kanuuna Oy + * + * 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 . + * + * + * Additional permission under GNU Affero General Public License version 3 + * section 7 + * + * If you modify this Program, or any covered work, by linking or combining it + * with other code, such other code is not for that reason alone subject to any + * of the requirements of the GNU Affero GPL version 3 as long as this Program + * is the same Program as licensed from Suomen Kanuuna Oy without any additional + * modifications. + * + * Supplemented terms under GNU Affero General Public License version 3 + * section 7 + * + * Origin of the software must be attributed to Suomen Kanuuna Oy. Any modified + * versions must be marked as "Modified version of" The Program. + * + * Names of the licensors and authors may not be used for publicity purposes. + * + * No rights are granted for use of trade names, trademarks, or service marks + * which are in The Program if any. + * + * Licensee must indemnify licensors and authors for any liability that these + * contractual assumptions impose on licensors and authors. + * + * To the extent this program is licensed as part of the Commercial versions of + * Teragrep, the applicable Commercial License may apply to this file if you as + * a licensee so wish it. + */ +package com.teragrep.rlp_11.Configuration; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.HashMap; +import java.util.Map; + +public class ProbeConfigurationTest { + + // probe.interval + @Test + public void testGoodInterval() { + Map map = baseConfig(); + ProbeConfiguration probeConfiguration = new ProbeConfiguration(map); + Assertions.assertEquals(12500, probeConfiguration.interval()); + } + + @Test + public void testNullInterval() { + Map map = baseConfig(); + map.remove("probe.interval"); + ProbeConfiguration probeConfiguration = new ProbeConfiguration(map); + Assertions.assertThrowsExactly(ConfigurationException.class, probeConfiguration::interval); + } + + @Test + public void testTooSmallInterval() { + Map map = baseConfig(); + map.put("probe.interval", "0"); + ProbeConfiguration probeConfiguration = new ProbeConfiguration(map); + Assertions.assertThrowsExactly(ConfigurationException.class, probeConfiguration::interval); + } + + @Test + public void testNonNumericInterval() { + Map map = baseConfig(); + map.put("probe.interval", "not a number"); + ProbeConfiguration probeConfiguration = new ProbeConfiguration(map); + Assertions.assertThrowsExactly(NumberFormatException.class, probeConfiguration::interval); + } + + private Map baseConfig() { + Map map = new HashMap<>(); + map.put("probe.interval", "12500"); + return map; + } +} diff --git a/src/test/java/com/teragrep/rlp_11/Configuration/PrometheusConfigurationTest.java b/src/test/java/com/teragrep/rlp_11/Configuration/PrometheusConfigurationTest.java new file mode 100644 index 0000000..008e6f4 --- /dev/null +++ b/src/test/java/com/teragrep/rlp_11/Configuration/PrometheusConfigurationTest.java @@ -0,0 +1,101 @@ +/* + * RELP Commit Latency Probe RLP-11 + * Copyright (C) 2024 Suomen Kanuuna Oy + * + * 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 . + * + * + * Additional permission under GNU Affero General Public License version 3 + * section 7 + * + * If you modify this Program, or any covered work, by linking or combining it + * with other code, such other code is not for that reason alone subject to any + * of the requirements of the GNU Affero GPL version 3 as long as this Program + * is the same Program as licensed from Suomen Kanuuna Oy without any additional + * modifications. + * + * Supplemented terms under GNU Affero General Public License version 3 + * section 7 + * + * Origin of the software must be attributed to Suomen Kanuuna Oy. Any modified + * versions must be marked as "Modified version of" The Program. + * + * Names of the licensors and authors may not be used for publicity purposes. + * + * No rights are granted for use of trade names, trademarks, or service marks + * which are in The Program if any. + * + * Licensee must indemnify licensors and authors for any liability that these + * contractual assumptions impose on licensors and authors. + * + * To the extent this program is licensed as part of the Commercial versions of + * Teragrep, the applicable Commercial License may apply to this file if you as + * a licensee so wish it. + */ +package com.teragrep.rlp_11.Configuration; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.HashMap; +import java.util.Map; + +public class PrometheusConfigurationTest { + + // prometheus.port + @Test + public void testGoodPort() { + Map map = baseConfig(); + PrometheusConfiguration prometheusConfiguration = new PrometheusConfiguration(map); + Assertions.assertEquals(8080, prometheusConfiguration.port()); + } + + @Test + public void testNullPort() { + Map map = baseConfig(); + map.remove("prometheus.port"); + PrometheusConfiguration prometheusConfiguration = new PrometheusConfiguration(map); + Assertions.assertThrowsExactly(ConfigurationException.class, prometheusConfiguration::port); + } + + @Test + public void testTooSmallPort() { + Map map = baseConfig(); + map.put("prometheus.port", "0"); + PrometheusConfiguration prometheusConfiguration = new PrometheusConfiguration(map); + Assertions.assertThrowsExactly(ConfigurationException.class, prometheusConfiguration::port); + } + + @Test + public void testTooHighPort() { + Map map = baseConfig(); + map.put("prometheus.port", "65536"); + PrometheusConfiguration prometheusConfiguration = new PrometheusConfiguration(map); + Assertions.assertThrowsExactly(ConfigurationException.class, prometheusConfiguration::port); + } + + @Test + public void testNonNumericPort() { + Map map = baseConfig(); + map.put("prometheus.port", "not a number"); + PrometheusConfiguration prometheusConfiguration = new PrometheusConfiguration(map); + Assertions.assertThrowsExactly(NumberFormatException.class, prometheusConfiguration::port); + } + + private Map baseConfig() { + Map map = new HashMap<>(); + map.put("prometheus.port", "8080"); + return map; + } +} diff --git a/src/test/java/com/teragrep/rlp_11/Configuration/RecordConfigurationTest.java b/src/test/java/com/teragrep/rlp_11/Configuration/RecordConfigurationTest.java new file mode 100644 index 0000000..ee53329 --- /dev/null +++ b/src/test/java/com/teragrep/rlp_11/Configuration/RecordConfigurationTest.java @@ -0,0 +1,94 @@ +/* + * RELP Commit Latency Probe RLP-11 + * Copyright (C) 2024 Suomen Kanuuna Oy + * + * 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 . + * + * + * Additional permission under GNU Affero General Public License version 3 + * section 7 + * + * If you modify this Program, or any covered work, by linking or combining it + * with other code, such other code is not for that reason alone subject to any + * of the requirements of the GNU Affero GPL version 3 as long as this Program + * is the same Program as licensed from Suomen Kanuuna Oy without any additional + * modifications. + * + * Supplemented terms under GNU Affero General Public License version 3 + * section 7 + * + * Origin of the software must be attributed to Suomen Kanuuna Oy. Any modified + * versions must be marked as "Modified version of" The Program. + * + * Names of the licensors and authors may not be used for publicity purposes. + * + * No rights are granted for use of trade names, trademarks, or service marks + * which are in The Program if any. + * + * Licensee must indemnify licensors and authors for any liability that these + * contractual assumptions impose on licensors and authors. + * + * To the extent this program is licensed as part of the Commercial versions of + * Teragrep, the applicable Commercial License may apply to this file if you as + * a licensee so wish it. + */ +package com.teragrep.rlp_11.Configuration; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.HashMap; +import java.util.Map; + +public class RecordConfigurationTest { + + // event.hostname + @Test + public void testNonNullHostname() { + Map map = baseConfig(); + RecordConfiguration eventConfiguration = new RecordConfiguration(map); + Assertions.assertEquals("my-hostname", eventConfiguration.hostname()); + } + + @Test + public void testNullHostname() { + Map map = baseConfig(); + map.remove("record.hostname"); + RecordConfiguration eventConfiguration = new RecordConfiguration(map); + Assertions.assertThrowsExactly(ConfigurationException.class, eventConfiguration::hostname); + } + + // event.appname + @Test + public void testNonNullAppname() { + Map map = baseConfig(); + RecordConfiguration eventConfiguration = new RecordConfiguration(map); + Assertions.assertEquals("my-appname", eventConfiguration.appname()); + } + + @Test + public void testNullAppname() { + Map map = baseConfig(); + map.remove("record.appname"); + RecordConfiguration eventConfiguration = new RecordConfiguration(map); + Assertions.assertThrowsExactly(ConfigurationException.class, eventConfiguration::appname); + } + + private Map baseConfig() { + Map map = new HashMap<>(); + map.put("record.hostname", "my-hostname"); + map.put("record.appname", "my-appname"); + return map; + } +} diff --git a/src/test/java/com/teragrep/rlp_11/Configuration/TargetConfigurationTest.java b/src/test/java/com/teragrep/rlp_11/Configuration/TargetConfigurationTest.java new file mode 100644 index 0000000..9fe0693 --- /dev/null +++ b/src/test/java/com/teragrep/rlp_11/Configuration/TargetConfigurationTest.java @@ -0,0 +1,151 @@ +/* + * RELP Commit Latency Probe RLP-11 + * Copyright (C) 2024 Suomen Kanuuna Oy + * + * 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 . + * + * + * Additional permission under GNU Affero General Public License version 3 + * section 7 + * + * If you modify this Program, or any covered work, by linking or combining it + * with other code, such other code is not for that reason alone subject to any + * of the requirements of the GNU Affero GPL version 3 as long as this Program + * is the same Program as licensed from Suomen Kanuuna Oy without any additional + * modifications. + * + * Supplemented terms under GNU Affero General Public License version 3 + * section 7 + * + * Origin of the software must be attributed to Suomen Kanuuna Oy. Any modified + * versions must be marked as "Modified version of" The Program. + * + * Names of the licensors and authors may not be used for publicity purposes. + * + * No rights are granted for use of trade names, trademarks, or service marks + * which are in The Program if any. + * + * Licensee must indemnify licensors and authors for any liability that these + * contractual assumptions impose on licensors and authors. + * + * To the extent this program is licensed as part of the Commercial versions of + * Teragrep, the applicable Commercial License may apply to this file if you as + * a licensee so wish it. + */ +package com.teragrep.rlp_11.Configuration; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.HashMap; +import java.util.Map; + +public class TargetConfigurationTest { + + // target.hostname + @Test + public void testNonNullHostname() { + Map map = baseConfig(); + TargetConfiguration targetConfiguration = new TargetConfiguration(map); + Assertions.assertEquals("target-hostname", targetConfiguration.hostname()); + } + + @Test + public void testNullHostname() { + Map map = baseConfig(); + map.remove("target.hostname"); + TargetConfiguration targetConfiguration = new TargetConfiguration(map); + Assertions.assertThrowsExactly(ConfigurationException.class, targetConfiguration::hostname); + } + + // target.port + @Test + public void testGoodPort() { + Map map = baseConfig(); + TargetConfiguration targetConfiguration = new TargetConfiguration(map); + Assertions.assertEquals(601, targetConfiguration.port()); + } + + @Test + public void testNullPort() { + Map map = baseConfig(); + map.remove("target.port"); + TargetConfiguration targetConfiguration = new TargetConfiguration(map); + Assertions.assertThrowsExactly(ConfigurationException.class, targetConfiguration::port); + } + + @Test + public void testTooSmallPort() { + Map map = baseConfig(); + map.put("target.port", "0"); + TargetConfiguration targetConfiguration = new TargetConfiguration(map); + Assertions.assertThrowsExactly(ConfigurationException.class, targetConfiguration::port); + } + + @Test + public void testTooHighPort() { + Map map = baseConfig(); + map.put("target.port", "65536"); + TargetConfiguration targetConfiguration = new TargetConfiguration(map); + Assertions.assertThrowsExactly(ConfigurationException.class, targetConfiguration::port); + } + + @Test + public void testNonNumericPort() { + Map map = baseConfig(); + map.put("target.port", "not a number"); + TargetConfiguration targetConfiguration = new TargetConfiguration(map); + Assertions.assertThrowsExactly(NumberFormatException.class, targetConfiguration::port); + } + + // target.reconnectinterval + @Test + public void testGoodReconnectInterval() { + Map map = baseConfig(); + TargetConfiguration targetConfiguration = new TargetConfiguration(map); + Assertions.assertEquals(15000, targetConfiguration.reconnectInterval()); + } + + @Test + public void testNullReconnectInterval() { + Map map = baseConfig(); + map.remove("target.reconnectinterval"); + TargetConfiguration targetConfiguration = new TargetConfiguration(map); + Assertions.assertThrowsExactly(ConfigurationException.class, targetConfiguration::reconnectInterval); + } + + @Test + public void testTooSmallReconnectInterval() { + Map map = baseConfig(); + map.put("target.reconnectinterval", "0"); + TargetConfiguration targetConfiguration = new TargetConfiguration(map); + Assertions.assertThrowsExactly(ConfigurationException.class, targetConfiguration::reconnectInterval); + } + + @Test + public void testNonNumericReconnectInterval() { + Map map = baseConfig(); + map.put("target.reconnectinterval", "not a number"); + TargetConfiguration targetConfiguration = new TargetConfiguration(map); + Assertions.assertThrowsExactly(NumberFormatException.class, targetConfiguration::reconnectInterval); + } + + private Map baseConfig() { + Map map = new HashMap<>(); + map.put("target.hostname", "target-hostname"); + map.put("target.port", "601"); + map.put("target.reconnectinterval", "15000"); + return map; + } +} diff --git a/src/test/java/com/teragrep/rlp_11/ConnectionTest.java b/src/test/java/com/teragrep/rlp_11/ConnectionTest.java new file mode 100644 index 0000000..d9fd278 --- /dev/null +++ b/src/test/java/com/teragrep/rlp_11/ConnectionTest.java @@ -0,0 +1,153 @@ +/* + * RELP Commit Latency Probe RLP-11 + * Copyright (C) 2024 Suomen Kanuuna Oy + * + * 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 . + * + * + * Additional permission under GNU Affero General Public License version 3 + * section 7 + * + * If you modify this Program, or any covered work, by linking or combining it + * with other code, such other code is not for that reason alone subject to any + * of the requirements of the GNU Affero GPL version 3 as long as this Program + * is the same Program as licensed from Suomen Kanuuna Oy without any additional + * modifications. + * + * Supplemented terms under GNU Affero General Public License version 3 + * section 7 + * + * Origin of the software must be attributed to Suomen Kanuuna Oy. Any modified + * versions must be marked as "Modified version of" The Program. + * + * Names of the licensors and authors may not be used for publicity purposes. + * + * No rights are granted for use of trade names, trademarks, or service marks + * which are in The Program if any. + * + * Licensee must indemnify licensors and authors for any liability that these + * contractual assumptions impose on licensors and authors. + * + * To the extent this program is licensed as part of the Commercial versions of + * Teragrep, the applicable Commercial License may apply to this file if you as + * a licensee so wish it. + */ +package com.teragrep.rlp_11; + +import com.teragrep.cnf_01.PathConfiguration; +import com.teragrep.net_01.channel.socket.PlainFactory; +import com.teragrep.net_01.eventloop.EventLoop; +import com.teragrep.net_01.eventloop.EventLoopFactory; +import com.teragrep.net_01.server.Server; +import com.teragrep.net_01.server.ServerFactory; +import com.teragrep.rlp_03.frame.FrameDelegationClockFactory; +import com.teragrep.rlp_03.frame.delegate.DefaultFrameDelegate; +import com.teragrep.rlp_03.frame.delegate.FrameDelegate; +import com.teragrep.rlp_11.Configuration.ProbeConfiguration; +import com.teragrep.rlp_11.Configuration.MetricsConfiguration; +import com.teragrep.rlp_11.Configuration.PrometheusConfiguration; +import com.teragrep.rlp_11.Configuration.TargetConfiguration; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; + +public class ConnectionTest { + + private final int serverPort = 12345; + private Thread eventLoopThread; + private EventLoop eventLoop; + private ThreadPoolExecutor threadPoolExecutor; + private final List records = new ArrayList<>(); + private Server server; + + @BeforeEach + public void startServer() { + EventLoopFactory eventLoopFactory = new EventLoopFactory(); + eventLoop = Assertions.assertDoesNotThrow(eventLoopFactory::create); + + eventLoopThread = new Thread(eventLoop); + eventLoopThread.start(); + + Supplier frameDelegateSupplier = () -> new DefaultFrameDelegate((frameContext) -> { + // Adds random latency before finishing and acking the event + Assertions.assertDoesNotThrow(() -> Thread.sleep((long) (Math.random() * 500))); + records.add(frameContext.relpFrame().payload().toString()); + }); + + threadPoolExecutor = new ThreadPoolExecutor( + 1, + 1, + Long.MAX_VALUE, + TimeUnit.SECONDS, + new LinkedBlockingQueue<>() + ); + ServerFactory serverFactory = new ServerFactory( + eventLoop, + threadPoolExecutor, + new PlainFactory(), + new FrameDelegationClockFactory(frameDelegateSupplier) + ); + server = Assertions.assertDoesNotThrow(() -> serverFactory.create(serverPort)); + } + + @AfterEach + public void stopServer() { + eventLoop.stop(); + threadPoolExecutor.shutdown(); + Assertions.assertDoesNotThrow(() -> eventLoopThread.join()); + Assertions.assertDoesNotThrow(server::close); + records.clear(); + } + + @Test + public void connectToServerTest() { + Map map = Assertions + .assertDoesNotThrow(() -> new PathConfiguration("src/test/resources/connectiontest.properties").asMap()); + final PrometheusConfiguration prometheusConfiguration = new PrometheusConfiguration(map); + final ProbeConfiguration probeConfiguration = new ProbeConfiguration(map); + final RecordFactory recordFactory = new RecordFactory("localhost", "rlp_11", "rlp_11"); + final TargetConfiguration targetConfiguration = new TargetConfiguration(map); + final MetricsConfiguration metricsConfiguration = new MetricsConfiguration(map); + + RelpProbe relpProbe = new RelpProbe( + targetConfiguration, + probeConfiguration, + prometheusConfiguration, + metricsConfiguration, + recordFactory + ); + + TimerTask task = new TimerTask() { + + public void run() { + relpProbe.stop(); + } + }; + Timer timer = new Timer("Timer"); + timer.schedule(task, 5_000L); + + relpProbe.start(); + } +} diff --git a/src/test/resources/connectiontest.properties b/src/test/resources/connectiontest.properties new file mode 100644 index 0000000..079c639 --- /dev/null +++ b/src/test/resources/connectiontest.properties @@ -0,0 +1,22 @@ +# Metrics reporting name. Arbitrary string, only used for reporting purposes +metrics.name=target +# Metrics window size +metrics.window=10000 + +# Delay between sending events, in milliseconds +probe.interval=1000 + +# Prometheus endpoint port +prometheus.port=8080 + +# Appname used in RELP record +record.appname=rlp_11 +# Hostname used in RELP record +record.hostname=rlp_11 + +# RELP Server target address +target.hostname=127.0.0.1 +# Relp Server target port +target.port=12345 +# RELP Server reconnect interval +target.reconnectinterval=1000 diff --git a/src/test/resources/missing.properties b/src/test/resources/missing.properties new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/test/resources/missing.properties @@ -0,0 +1 @@ +