Skip to content

Commit

Permalink
Implement Spring Boot Actuator
Browse files Browse the repository at this point in the history
  • Loading branch information
schnapster committed Nov 10, 2024
1 parent 86b577f commit 052565f
Show file tree
Hide file tree
Showing 21 changed files with 228 additions and 247 deletions.
2 changes: 2 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,7 @@ dependencies {
implementation "io.prometheus:simpleclient_common"
implementation "io.prometheus:simpleclient_caffeine"
implementation "space.npstr:prometheus_extensions:$promExtVersion"
implementation "io.micrometer:micrometer-registry-prometheus"

implementation "org.postgresql:postgresql"
implementation "com.zaxxer:HikariCP"
Expand All @@ -318,6 +319,7 @@ dependencies {
implementation "org.springframework.boot:spring-boot-starter-security"
implementation "org.springframework.boot:spring-boot-starter-data-jpa"
implementation "org.springframework.boot:spring-boot-starter-oauth2-client"
implementation "org.springframework.boot:spring-boot-starter-actuator"
implementation "org.springframework.session:spring-session-data-redis"
implementation "org.jetbrains.kotlin:kotlin-reflect"
implementation "com.fasterxml.jackson.module:jackson-module-kotlin"
Expand Down
8 changes: 8 additions & 0 deletions gradle.lockfile
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,10 @@ commons-io:commons-io:2.17.0=testRuntimeClasspath
dev.failsafe:failsafe:3.3.2=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
io.lettuce:lettuce-core:6.3.2.RELEASE=compileClasspath,implementationDependenciesMetadata,productionRuntimeClasspath,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
io.micrometer:micrometer-commons:1.12.11=compileClasspath,compileOnlyDependenciesMetadata,implementationDependenciesMetadata,productionRuntimeClasspath,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
io.micrometer:micrometer-core:1.12.11=compileClasspath,implementationDependenciesMetadata,productionRuntimeClasspath,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
io.micrometer:micrometer-jakarta9:1.12.11=compileClasspath,implementationDependenciesMetadata,productionRuntimeClasspath,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
io.micrometer:micrometer-observation:1.12.11=compileClasspath,compileOnlyDependenciesMetadata,implementationDependenciesMetadata,productionRuntimeClasspath,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
io.micrometer:micrometer-registry-prometheus:1.12.11=compileClasspath,implementationDependenciesMetadata,productionRuntimeClasspath,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
io.netty:netty-buffer:4.1.114.Final=compileClasspath,implementationDependenciesMetadata,productionRuntimeClasspath,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
io.netty:netty-codec:4.1.114.Final=compileClasspath,implementationDependenciesMetadata,productionRuntimeClasspath,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
io.netty:netty-common:4.1.114.Final=compileClasspath,implementationDependenciesMetadata,productionRuntimeClasspath,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
Expand Down Expand Up @@ -159,6 +162,7 @@ org.glassfish.jaxb:jaxb-runtime:4.0.5=jooqGenerator,productionRuntimeClasspath,r
org.glassfish.jaxb:txw2:4.0.5=jooqGenerator,productionRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
org.hamcrest:hamcrest-core:2.2=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.hamcrest:hamcrest:2.2=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.hdrhistogram:HdrHistogram:2.1.12=productionRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
org.hibernate.common:hibernate-commons-annotations:6.0.6.Final=productionRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
org.hibernate.orm:hibernate-core:6.4.10.Final=compileClasspath,implementationDependenciesMetadata,productionRuntimeClasspath,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.jacoco:org.jacoco.agent:0.8.12=jacocoAgent,jacocoAnt
Expand Down Expand Up @@ -211,6 +215,7 @@ org.junit.platform:junit-platform-commons:1.10.5=testCompileClasspath,testImplem
org.junit.platform:junit-platform-engine:1.10.5=testRuntimeClasspath
org.junit.platform:junit-platform-launcher:1.10.5=testRuntimeClasspath
org.junit:junit-bom:5.10.5=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.latencyutils:LatencyUtils:2.0.3=productionRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
org.mockito.kotlin:mockito-kotlin:5.4.0=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.mockito:mockito-core:5.12.0=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.mockito:mockito-junit-jupiter:5.7.0=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
Expand Down Expand Up @@ -250,11 +255,14 @@ org.seleniumhq.selenium:selenium-support:4.25.0=testCompileClasspath,testImpleme
org.skyscreamer:jsonassert:1.5.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.slf4j:jul-to-slf4j:2.0.16=compileClasspath,implementationDependenciesMetadata,productionRuntimeClasspath,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.slf4j:slf4j-api:2.0.16=compileClasspath,implementationDependenciesMetadata,productionRuntimeClasspath,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.springframework.boot:spring-boot-actuator-autoconfigure:3.2.11=compileClasspath,implementationDependenciesMetadata,productionRuntimeClasspath,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.springframework.boot:spring-boot-actuator:3.2.11=compileClasspath,implementationDependenciesMetadata,productionRuntimeClasspath,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.springframework.boot:spring-boot-autoconfigure:3.2.11=compileOnlyDependenciesMetadata
org.springframework.boot:spring-boot-autoconfigure:3.3.2=compileClasspath,implementationDependenciesMetadata,productionRuntimeClasspath,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.springframework.boot:spring-boot-configuration-processor:3.2.11=annotationProcessor
org.springframework.boot:spring-boot-dependencies:3.2.11=annotationProcessor,apiDependenciesMetadata,compile,compileClasspath,compileOnlyDependenciesMetadata,developmentOnly,flywayMigration,implementationDependenciesMetadata,intransitiveDependenciesMetadata,jacocoAgent,jacocoAnt,jooqGenerator,kotlinBuildToolsApiClasspath,kotlinCompilerClasspath,kotlinCompilerPluginClasspath,kotlinCompilerPluginClasspathMain,kotlinCompilerPluginClasspathTest,kotlinKlibCommonizerClasspath,kotlinNativeCompilerPluginClasspath,kotlinScriptDef,kotlinScriptDefExtensions,productionRuntimeClasspath,runtimeClasspath,testAndDevelopmentOnly,testAnnotationProcessor,testApiDependenciesMetadata,testCompileClasspath,testCompileOnlyDependenciesMetadata,testImplementationDependenciesMetadata,testIntransitiveDependenciesMetadata,testKotlinScriptDef,testKotlinScriptDefExtensions,testRuntimeClasspath
org.springframework.boot:spring-boot-devtools:3.2.11=compileClasspath,compileOnlyDependenciesMetadata
org.springframework.boot:spring-boot-starter-actuator:3.2.11=compileClasspath,implementationDependenciesMetadata,productionRuntimeClasspath,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.springframework.boot:spring-boot-starter-aop:3.2.11=compileClasspath,implementationDependenciesMetadata,productionRuntimeClasspath,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.springframework.boot:spring-boot-starter-data-jpa:3.2.11=compileClasspath,implementationDependenciesMetadata,productionRuntimeClasspath,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.springframework.boot:spring-boot-starter-jdbc:3.2.11=compileClasspath,implementationDependenciesMetadata,productionRuntimeClasspath,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
Expand Down
9 changes: 6 additions & 3 deletions src/main/java/space/npstr/wolfia/commands/CommandContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import org.springframework.lang.Nullable;
import space.npstr.wolfia.system.metrics.MetricsService;
import space.npstr.wolfia.utils.discord.RestActions;

/**
Expand All @@ -35,6 +36,7 @@ public class CommandContext extends MessageContext {

private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(CommandContext.class);

private final MetricsService metricsService;
//@formatter:off
public final String trigger; // the command trigger, e.g. "play", or "p", or "pLaY", whatever the user typed
public final String[] args ; // the arguments split by whitespace, excluding prefix and trigger
Expand All @@ -43,10 +45,11 @@ public class CommandContext extends MessageContext {
// private final Histogram.Timer received; // time when we received this command
//@formatter:on

CommandContext(MessageReceivedEvent event, String trigger,
CommandContext(MessageReceivedEvent event, MetricsService metricsService, String trigger,
String[] args, String rawArgs, BaseCommand command) {

super(event);
super(event, metricsService);
this.metricsService = metricsService;
this.trigger = trigger;
this.args = args;
this.rawArgs = rawArgs;
Expand Down Expand Up @@ -89,7 +92,7 @@ public GuildCommandContext requireGuild(boolean... answerUser) {
Guild g = tc.getGuild();
Member m = this.event.getMember();
if (m != null) {
return new GuildCommandContext(this, g, m, tc);
return new GuildCommandContext(this, metricsService, g, m, tc);
} else {
log.warn("Uh oh member is unexpectedly null when transforming CommandContext to GuildCommandContext");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,22 @@

package space.npstr.wolfia.commands;

import java.util.Arrays;
import java.util.regex.Pattern;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import org.springframework.stereotype.Component;
import space.npstr.wolfia.config.properties.WolfiaConfig;

import java.util.Arrays;
import java.util.regex.Pattern;
import space.npstr.wolfia.system.metrics.MetricsService;

@Component
public class CommandContextParser {

private final MetricsService metricsService;

public CommandContextParser(MetricsService metricsService) {
this.metricsService = metricsService;
}

/**
* @param event the event to be parsed
* @return The full context for the triggered command, or null if it's not a command that we know.
Expand Down Expand Up @@ -61,7 +67,7 @@ public CommandContext parse(CommRegistry commRegistry, MessageReceivedEvent even
if (command == null) {
return null;
} else {
return new CommandContext(event, commandTrigger,
return new CommandContext(event, metricsService, commandTrigger,
Arrays.copyOfRange(args, 1, args.length),//exclude args[0] that contains the command trigger
input.replaceFirst(Pattern.quote(commandTrigger), "").trim(),
command
Expand Down
10 changes: 6 additions & 4 deletions src/main/java/space/npstr/wolfia/commands/CommandHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
import space.npstr.wolfia.game.Game;
import space.npstr.wolfia.game.exceptions.IllegalGameStateException;
import space.npstr.wolfia.system.ApplicationInfoProvider;
import space.npstr.wolfia.system.metrics.MetricsRegistry;
import space.npstr.wolfia.system.metrics.MetricsService;
import space.npstr.wolfia.utils.UserFriendlyException;
import space.npstr.wolfia.utils.discord.RestActions;
import space.npstr.wolfia.utils.discord.TextchatUtils;
Expand All @@ -70,21 +70,23 @@ public class CommandHandler {
private final CommRegistry commRegistry;
private final ChannelSettingsService channelSettingsService;
private final PrivacyService privacyService;
private final MetricsService metricsService;

public CommandHandler(GameRegistry gameRegistry, CommandContextParser commandContextParser,
CommRegistry commRegistry, ChannelSettingsService channelSettingsService,
PrivacyService privacyService) {
PrivacyService privacyService, MetricsService metricsService) {

this.gameRegistry = gameRegistry;
this.commandContextParser = commandContextParser;
this.commRegistry = commRegistry;
this.channelSettingsService = channelSettingsService;
this.privacyService = privacyService;
this.metricsService = metricsService;
}

@EventListener
public void onMessageReceived(MessageReceivedEvent event) {
Timer received = MetricsRegistry.commandRetentionTime.startTimer();
Timer received = metricsService.commandRetentionTime.startTimer();
//ignore bot accounts generally
if (event.getAuthor().isBot()) {
return;
Expand Down Expand Up @@ -189,7 +191,7 @@ private void handleCommand(CommandContext context, Timer received) {
context.invoker, context.channel, context.msg.getContentRaw());

received.observeDuration();//retention
try (Summary.Timer ignored = MetricsRegistry.commandProcessTime.labels(context.command.getClass().getSimpleName()).startTimer()) {
try (Summary.Timer ignored = metricsService.commandProcessTime.labels(context.command.getClass().getSimpleName()).startTimer()) {
context.command.execute(context);
}
} catch (UserFriendlyException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
import space.npstr.wolfia.system.metrics.MetricsService;

/**
* Provides non-null methods for accessing guild entities after an elegant transformation from a CommandContext
Expand Down Expand Up @@ -48,9 +49,9 @@ public TextChannel getTextChannel() {
return this.textChannel;
}

public GuildCommandContext(CommandContext context, Guild guild,
public GuildCommandContext(CommandContext context, MetricsService metricsService, Guild guild,
Member member, TextChannel textChannel) {
super(context.event, context.trigger, context.args, context.rawArgs, context.command);
super(context.event, metricsService, context.trigger, context.args, context.rawArgs, context.command);
this.guild = guild;
this.member = member;
this.textChannel = textChannel;
Expand Down
10 changes: 6 additions & 4 deletions src/main/java/space/npstr/wolfia/commands/MessageContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
import net.dv8tion.jda.api.utils.messages.MessageCreateData;
import org.springframework.lang.Nullable;
import space.npstr.wolfia.system.ApplicationInfoProvider;
import space.npstr.wolfia.system.metrics.MetricsRegistry;
import space.npstr.wolfia.system.metrics.MetricsService;
import space.npstr.wolfia.utils.discord.RestActions;
import space.npstr.wolfia.utils.discord.TextchatUtils;

Expand All @@ -52,16 +52,18 @@ public class MessageContext implements Context {
public final Message msg;
public final MessageReceivedEvent event;
public final JDA jda;
private final MetricsService metricsService;

private final ApplicationInfoProvider appInfoProvider;

public MessageContext(MessageReceivedEvent event) {
public MessageContext(MessageReceivedEvent event, MetricsService metricsService) {
this.channel = event.getChannel();
this.invoker = event.getAuthor();
this.msg = event.getMessage();
this.event = event;
this.jda = event.getJDA();
this.appInfoProvider = new ApplicationInfoProvider(event.getJDA().getShardManager());
this.metricsService = metricsService;
}


Expand Down Expand Up @@ -181,10 +183,10 @@ private void reply0(MessageCreateData message, @Nullable Consumer<Message> onSuc
long started = System.nanoTime();

Consumer<Message> successWrapper = m -> {
MetricsRegistry.commandResponseTime.observe((System.nanoTime() - started) / Collector.NANOSECONDS_PER_SECOND);
metricsService.commandResponseTime.observe((System.nanoTime() - started) / Collector.NANOSECONDS_PER_SECOND);
long in = getMessage().getTimeCreated().toInstant().toEpochMilli();
long out = m.getTimeCreated().toInstant().toEpochMilli();
MetricsRegistry.commandTotalTime.observe((out - in) / Collector.MILLISECONDS_PER_SECOND);
metricsService.commandTotalTime.observe((out - in) / Collector.MILLISECONDS_PER_SECOND);
if (onSuccess != null) {
onSuccess.accept(m);
}
Expand Down
39 changes: 27 additions & 12 deletions src/main/java/space/npstr/wolfia/config/MetricsConfiguration.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,31 +17,43 @@

package space.npstr.wolfia.config;

import ch.qos.logback.classic.LoggerContext;
import io.prometheus.client.CollectorRegistry;
import io.prometheus.client.cache.caffeine.CacheMetricsCollector;
import io.prometheus.client.logback.InstrumentedAppender;
import java.util.concurrent.ScheduledExecutorService;
import net.dv8tion.jda.api.sharding.ShardManager;
import net.ttddyy.dsproxy.listener.SingleQueryCountHolder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import space.npstr.prometheus_extensions.QueryCountCollector;
import space.npstr.prometheus_extensions.ThreadPoolCollector;
import space.npstr.prometheus_extensions.jda.JdaMetrics;
import space.npstr.wolfia.system.metrics.MetricsRegistry;

@Configuration
public class MetricsConfiguration {

//caffeine cache metrics
@Bean
public CacheMetricsCollector cacheMetrics() {
return new CacheMetricsCollector().register();
public CacheMetricsCollector cacheMetrics(CollectorRegistry registry) {
return new CacheMetricsCollector().register(registry);
}

@Bean
public InstrumentedAppender instrumentedAppender() {
return new InstrumentedAppender();
public InstrumentedAppender instrumentedAppender(CollectorRegistry registry) {
var instrumentedAppender = new InstrumentedAppender(registry);

// register with logging framework
LoggerContext factory = (LoggerContext) LoggerFactory.getILoggerFactory();
var root = factory.getLogger(Logger.ROOT_LOGGER_NAME);
instrumentedAppender.setContext(root.getLoggerContext());
instrumentedAppender.start();
root.addAppender(instrumentedAppender);

return instrumentedAppender;
}

@Bean
Expand All @@ -50,19 +62,22 @@ public SingleQueryCountHolder queryCountHolder() {
}

@Bean
public QueryCountCollector queryCountCollector(SingleQueryCountHolder queryCountHolder) {
return new QueryCountCollector(queryCountHolder);
public QueryCountCollector queryCountCollector(SingleQueryCountHolder queryCountHolder, CollectorRegistry registry) {
return new QueryCountCollector(queryCountHolder).register(registry);
}

@Bean
public ThreadPoolCollector threadPoolCollector() {
return new ThreadPoolCollector();
public ThreadPoolCollector threadPoolCollector(CollectorRegistry registry) {
return new ThreadPoolCollector().register(registry);
}

@Bean
public JdaMetrics jdaMetrics(ShardManager shardManager, @Qualifier("jdaThreadPool") ScheduledExecutorService scheduler,
MetricsRegistry metricsRegistry) {
public JdaMetrics jdaMetrics(
ShardManager shardManager,
@Qualifier("jdaThreadPool") ScheduledExecutorService scheduler,
CollectorRegistry registry
) {

return new JdaMetrics(shardManager, scheduler, metricsRegistry.getRegistry());
return new JdaMetrics(shardManager, scheduler, registry);
}
}
Loading

0 comments on commit 052565f

Please sign in to comment.