Skip to content

Commit

Permalink
DropWizard metrics (#76)
Browse files Browse the repository at this point in the history
* Setup DropWizard metrics

* Add Prometheus port configuration to README

* Unit tests for metrics

* Add metrics, rewrite MetricTest based on the objects that handle the metrics

* Clear changed properties in MetricTest

* Change the name of sendLatency metric

* Move test classes to the correct packages

* Decorate NettyHttpServer with MetricHttpServer

* Close server in finally block in MetricHttpServer

* Change closing order in MetricHttpServer

* Refactor Metrics into Report and split the logic into decorators
  • Loading branch information
51-code authored Oct 8, 2024
1 parent 605ef1f commit ac44b1a
Show file tree
Hide file tree
Showing 26 changed files with 1,370 additions and 42 deletions.
1 change: 1 addition & 0 deletions README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ lookups.hostname.file,etc/hostname.json,Path to username-to-hostname lookup tabl
lookups.appname.file,etc/appname.json,Path to username-to-appname lookup table
payload.splitRegex, \n (newline), A regex based on which incoming requests will be split into multiple outgoing messages
payload.splitEnabled, false, Sets whether splitting incoming messages by splitRegex is enabled
prometheus.port, 1234, Port used by the server that provides DropWizard metrics
|===

=== Lookup tables
Expand Down
2 changes: 2 additions & 0 deletions etc/config.properties
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,5 @@ lookups.appname.file=etc/appname.json

payload.splitRegex=\n
payload.splitEnabled=false

prometheus.port=1234
39 changes: 39 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@
<log4j.version>2.23.1</log4j.version>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
<metrics.version>4.2.8</metrics.version>
<netty.version>4.1.108.Final</netty.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<prometheus-simpleclient.version>0.16.0</prometheus-simpleclient.version>
<revision>0.0.1</revision>
<rlo_14.version>1.0.1</rlo_14.version>
<rlp_01.version>4.0.1</rlp_01.version>
Expand Down Expand Up @@ -90,6 +92,43 @@
<artifactId>netty-handler</artifactId>
<version>${netty.version}</version>
</dependency>
<!-- metrics -->
<dependency>
<groupId>io.dropwizard.metrics</groupId>
<artifactId>metrics-core</artifactId>
<version>${metrics.version}</version>
</dependency>
<dependency>
<groupId>io.dropwizard.metrics</groupId>
<artifactId>metrics-jmx</artifactId>
<version>${metrics.version}</version>
</dependency>
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>simpleclient</artifactId>
<version>${prometheus-simpleclient.version}</version>
</dependency>
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>simpleclient_dropwizard</artifactId>
<version>${prometheus-simpleclient.version}</version>
</dependency>
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>simpleclient_servlet</artifactId>
<version>${prometheus-simpleclient.version}</version>
</dependency>
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>simpleclient_hotspot</artifactId>
<version>${prometheus-simpleclient.version}</version>
</dependency>
<!-- for exporting prometheus -->
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<version>10.0.15</version>
</dependency>
<!-- log4j -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
Expand Down
25 changes: 25 additions & 0 deletions src/main/java/com/teragrep/lsh_01/HttpServer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
logstash-http-input to syslog bridge
Copyright 2024 Suomen Kanuuna Oy
Derivative Work of Elasticsearch
Copyright 2012-2015 Elasticsearch
Licensed 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 com.teragrep.lsh_01;

import java.io.Closeable;

public interface HttpServer extends Runnable, Closeable {
}
39 changes: 26 additions & 13 deletions src/main/java/com/teragrep/lsh_01/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,20 @@
*/
package com.teragrep.lsh_01;

import com.codahale.metrics.MetricRegistry;
import com.teragrep.lsh_01.authentication.BasicAuthentication;
import com.teragrep.lsh_01.authentication.BasicAuthenticationFactory;
import com.teragrep.lsh_01.config.*;
import com.teragrep.lsh_01.metrics.HttpReport;
import com.teragrep.lsh_01.metrics.JmxReport;
import com.teragrep.lsh_01.metrics.Report;
import com.teragrep.lsh_01.metrics.Slf4jReport;
import com.teragrep.lsh_01.pool.*;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.IOException;

public class Main {

private final static Logger LOGGER = LogManager.getLogger(Main.class);
Expand All @@ -38,13 +45,15 @@ public static void main(String[] args) {
InternalEndpointUrlConfig internalEndpointUrlConfig = new InternalEndpointUrlConfig();
LookupConfig lookupConfig = new LookupConfig();
PayloadConfig payloadConfig = new PayloadConfig();
MetricsConfig metricsConfig = new MetricsConfig();
try {
nettyConfig.validate();
relpConfig.validate();
securityConfig.validate();
internalEndpointUrlConfig.validate();
lookupConfig.validate();
payloadConfig.validate();
metricsConfig.validate();
}
catch (IllegalArgumentException e) {
LOGGER.error("Can't parse config properly: {}", e.getMessage());
Expand All @@ -57,28 +66,32 @@ public static void main(String[] args) {
LOGGER.info("Got payload config: <[{}]>", payloadConfig);
LOGGER.info("Authentication required: <[{}]>", securityConfig.authRequired);

RelpConnectionFactory relpConnectionFactory = new RelpConnectionFactory(relpConfig);
// metrics
MetricRegistry metricRegistry = new MetricRegistry();
Report report = new Slf4jReport(
new JmxReport(new HttpReport(metricRegistry, metricsConfig.prometheusPort), metricRegistry),
metricRegistry
);

RelpConnectionFactory relpConnectionFactory = new RelpConnectionFactory(relpConfig, metricRegistry);
Pool<IManagedRelpConnection> pool = new Pool<>(relpConnectionFactory, new ManagedRelpConnectionStub());

RelpConversion relpConversion = new RelpConversion(
pool,
securityConfig,
basicAuthentication,
lookupConfig,
payloadConfig
IMessageHandler relpConversion = new MetricRelpConversion(
new RelpConversion(pool, securityConfig, basicAuthentication, lookupConfig, payloadConfig),
metricRegistry
);

try (
NettyHttpServer server = new NettyHttpServer(
nettyConfig,
relpConversion,
null,
200,
internalEndpointUrlConfig
HttpServer server = new MetricHttpServer(
new NettyHttpServer(nettyConfig, relpConversion, null, 200, internalEndpointUrlConfig),
report
)
) {
server.run();
}
catch (IOException e) {
throw new IllegalArgumentException("Failed to close the server: " + e.getMessage());
}
finally {
pool.close();
}
Expand Down
54 changes: 54 additions & 0 deletions src/main/java/com/teragrep/lsh_01/MetricHttpServer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
logstash-http-input to syslog bridge
Copyright 2024 Suomen Kanuuna Oy
Derivative Work of Elasticsearch
Copyright 2012-2015 Elasticsearch
Licensed 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 com.teragrep.lsh_01;

import com.teragrep.lsh_01.metrics.Report;

import java.io.IOException;

/**
* Decorator for a HttpServer that applies metrics.
*/
public class MetricHttpServer implements HttpServer {

private final HttpServer server;
private final Report report;

public MetricHttpServer(HttpServer server, Report report) {
this.server = server;
this.report = report;
}

@Override
public void run() {
report.start();
server.run();
}

@Override
public void close() throws IOException {
try {
server.close();
}
finally {
report.close();
}
}
}
75 changes: 75 additions & 0 deletions src/main/java/com/teragrep/lsh_01/MetricRelpConversion.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
logstash-http-input to syslog bridge
Copyright 2024 Suomen Kanuuna Oy
Derivative Work of Elasticsearch
Copyright 2012-2015 Elasticsearch
Licensed 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 com.teragrep.lsh_01;

import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.SlidingWindowReservoir;
import com.codahale.metrics.Timer;
import com.teragrep.lsh_01.authentication.Subject;

import java.util.Map;

import static com.codahale.metrics.MetricRegistry.name;

/**
* Decorator for IMessageHandler. Responsible for reporting metrics.
*/
public class MetricRelpConversion implements IMessageHandler {

private final IMessageHandler relpConversion;
private final MetricRegistry metricRegistry;
private final Timer sendLatency;

public MetricRelpConversion(IMessageHandler relpConversion, MetricRegistry metricRegistry) {
this.relpConversion = relpConversion;
this.metricRegistry = metricRegistry;
this.sendLatency = metricRegistry
.timer(name(MetricRelpConversion.class, "sendLatency"), () -> new Timer(new SlidingWindowReservoir(10000)));
}

@Override
public boolean onNewMessage(Subject subject, Map<String, String> headers, String body) {
boolean sent;
try (Timer.Context ctx = sendLatency.time()) {
sent = relpConversion.onNewMessage(subject, headers, body);
}
return sent;
}

@Override
public IMessageHandler copy() {
return new MetricRelpConversion(relpConversion.copy(), metricRegistry);
}

@Override
public Subject asSubject(String token) {
return relpConversion.asSubject(token);
}

@Override
public boolean requiresToken() {
return relpConversion.requiresToken();
}

@Override
public Map<String, String> responseHeaders() {
return relpConversion.responseHeaders();
}
}
3 changes: 1 addition & 2 deletions src/main/java/com/teragrep/lsh_01/NettyHttpServer.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
import com.teragrep.lsh_01.util.CustomRejectedExecutionHandler;
import com.teragrep.lsh_01.util.SslHandlerProvider;

import java.io.Closeable;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
Expand All @@ -41,7 +40,7 @@
/**
* Created by joaoduarte on 11/10/2017.
*/
public class NettyHttpServer implements Runnable, Closeable {
public class NettyHttpServer implements HttpServer {

private final ServerBootstrap serverBootstrap;
private final String host;
Expand Down
44 changes: 44 additions & 0 deletions src/main/java/com/teragrep/lsh_01/config/MetricsConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
logstash-http-input to syslog bridge
Copyright 2024 Suomen Kanuuna Oy
Derivative Work of Elasticsearch
Copyright 2012-2015 Elasticsearch
Licensed 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 com.teragrep.lsh_01.config;

public class MetricsConfig implements Validateable {

public final int prometheusPort;

public MetricsConfig() {
PropertiesReaderUtilityClass propertiesReader = new PropertiesReaderUtilityClass(
System.getProperty("properties.file", "etc/config.properties")
);
prometheusPort = propertiesReader.getIntProperty("prometheus.port");
}

@Override
public void validate() {
if (prometheusPort < 1 || prometheusPort > 65535) {
throw new IllegalArgumentException("prometheus.port wasn't a valid port");
}
}

@Override
public String toString() {
return "RelpConfig{" + "prometheusPort=" + prometheusPort + "}";
}
}
Loading

0 comments on commit ac44b1a

Please sign in to comment.