Skip to content

Commit 6114909

Browse files
authored
Merge pull request #776 from gsmet/opentelemetry-integration
OpenTelemetry integration + HTTP_PROXY support
2 parents 91f0a3f + 6ad7c76 commit 6114909

File tree

58 files changed

+3009
-148
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+3009
-148
lines changed

command-airline/deployment/src/main/java/io/quarkiverse/githubapp/command/airline/deployment/GitHubAppCommandAirlineProcessor.java

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import org.kohsuke.github.GHReaction;
3939
import org.kohsuke.github.ReactionContent;
4040

41+
import io.quarkiverse.githubapp.GitHubEvent;
4142
import io.quarkiverse.githubapp.command.airline.CliOptions.ParseErrorStrategy;
4243
import io.quarkiverse.githubapp.command.airline.CommandOptions.CommandScope;
4344
import io.quarkiverse.githubapp.command.airline.CommandOptions.ExecutionErrorStrategy;
@@ -55,6 +56,7 @@
5556
import io.quarkiverse.githubapp.command.airline.runtime.DefaultParseErrorHandler;
5657
import io.quarkiverse.githubapp.command.airline.runtime.util.Reactions;
5758
import io.quarkiverse.githubapp.deployment.AdditionalEventDispatchingClassesIndexBuildItem;
59+
import io.quarkiverse.githubapp.deployment.GitHubAppDotNames;
5860
import io.quarkus.arc.deployment.AdditionalBeanBuildItem;
5961
import io.quarkus.arc.deployment.AnnotationsTransformerBuildItem;
6062
import io.quarkus.arc.deployment.BeanDefiningAnnotationBuildItem;
@@ -191,20 +193,26 @@ private static void generateCommandDispatcherDispatchMethod(ClassCreator command
191193
.filter(ai -> ai.target().kind() == Kind.METHOD_PARAMETER)
192194
.collect(Collectors.groupingBy(ai -> ai.target().asMethodParameter().position()));
193195

196+
short gitHubEventPosition = -1;
194197
short issueCommentPayloadPosition = -1;
195-
boolean originalMethodHasIssueCommentPayloadParameter = false;
196198

197199
for (short i = 0; i < originalMethodParameterTypes.size(); i++) {
200+
if (GitHubAppDotNames.GITHUB_EVENT.equals(originalMethodParameterTypes.get(i).name())) {
201+
gitHubEventPosition = i;
202+
}
198203
if (GH_EVENT_PAYLOAD_ISSUE_COMMENT.equals(originalMethodParameterTypes.get(i).name())) {
199204
issueCommentPayloadPosition = i;
200-
originalMethodHasIssueCommentPayloadParameter = true;
201205
}
202206
}
203207

204208
List<String> parameterTypes = new ArrayList<>();
205209
originalMethodParameterTypes.stream().map(t -> t.name().toString())
206210
.forEach(parameterTypes::add);
207-
if (!originalMethodHasIssueCommentPayloadParameter) {
211+
if (gitHubEventPosition < 0) {
212+
parameterTypes.add(GitHubAppDotNames.GITHUB_EVENT.toString());
213+
gitHubEventPosition = (short) (parameterTypes.size() - 1);
214+
}
215+
if (issueCommentPayloadPosition < 0) {
208216
parameterTypes.add(GH_EVENT_PAYLOAD_ISSUE_COMMENT.toString());
209217
issueCommentPayloadPosition = (short) (parameterTypes.size() - 1);
210218
}
@@ -226,17 +234,18 @@ private static void generateCommandDispatcherDispatchMethod(ClassCreator command
226234
}
227235
}
228236
}
229-
if (!originalMethodHasIssueCommentPayloadParameter) {
237+
if (issueCommentPayloadPosition < 0) {
230238
dispatchMethodCreator.getParameterAnnotations(issueCommentPayloadPosition)
231239
.addAnnotation(ISSUE_COMMENT_CREATED.toString());
232240
}
233241

234242
ResultHandle issueCommentPayloadRh = dispatchMethodCreator.getMethodParam(issueCommentPayloadPosition);
243+
ResultHandle gitHubEventRh = dispatchMethodCreator.getMethodParam(gitHubEventPosition);
235244

236245
ResultHandle commandExecutionContextOptional = dispatchMethodCreator.invokeSpecialMethod(
237246
MethodDescriptor.ofMethod(AbstractCommandDispatcher.class, "getCommand", Optional.class,
238-
GHEventPayload.IssueComment.class),
239-
dispatchMethodCreator.getThis(), issueCommentPayloadRh);
247+
GitHubEvent.class, GHEventPayload.IssueComment.class),
248+
dispatchMethodCreator.getThis(), gitHubEventRh, issueCommentPayloadRh);
240249
BranchResult commandExecutionContextOptionalIsPresent = dispatchMethodCreator.ifTrue(dispatchMethodCreator
241250
.invokeVirtualMethod(MethodDescriptor.ofMethod(Optional.class, "isPresent", boolean.class),
242251
commandExecutionContextOptional));
@@ -271,6 +280,9 @@ private static void generateCommandDispatcherDispatchMethod(ClassCreator command
271280
}
272281
tryBlock.invokeInterfaceMethod(runMethod.getMethod(), commandRh,
273282
runMethodParameters.toArray(new ResultHandle[0]));
283+
tryBlock.invokeSpecialMethod(MethodDescriptor.ofMethod(AbstractCommandDispatcher.class, "handleSuccess",
284+
void.class, GitHubEvent.class, GHEventPayload.IssueComment.class, CommandExecutionContext.class),
285+
tryBlock.getThis(), gitHubEventRh, issueCommentPayloadRh, commandExecutionContextRh);
274286
deleteReaction(tryBlock, issueCommentPayloadRh, ackReactionRh);
275287
BranchResult reactionOnNormalFlow = tryBlock.ifTrue(tryBlock.invokeVirtualMethod(
276288
MethodDescriptor.ofMethod(ReactionStrategy.class, "reactionOnNormalFlow", boolean.class), reactionStrategyRh));
@@ -283,9 +295,9 @@ private static void generateCommandDispatcherDispatchMethod(ClassCreator command
283295
createReaction(reactionOnError.trueBranch(), issueCommentPayloadRh, ReactionContent.MINUS_ONE);
284296

285297
catchBlock.invokeSpecialMethod(MethodDescriptor.ofMethod(AbstractCommandDispatcher.class, "handleExecutionError",
286-
void.class, GHEventPayload.IssueComment.class, CommandExecutionContext.class, Exception.class),
287-
catchBlock.getThis(),
288-
issueCommentPayloadRh, commandExecutionContextRh, catchBlock.getCaughtException());
298+
void.class, GitHubEvent.class, GHEventPayload.IssueComment.class, CommandExecutionContext.class,
299+
Exception.class), catchBlock.getThis(),
300+
gitHubEventRh, issueCommentPayloadRh, commandExecutionContextRh, catchBlock.getCaughtException());
289301

290302
catchBlock.throwException(catchBlock
291303
.newInstance(MethodDescriptor.ofConstructor(CommandExecutionException.class, String.class, Exception.class),

command-airline/runtime/src/main/java/io/quarkiverse/githubapp/command/airline/runtime/AbstractCommandDispatcher.java

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
import java.util.List;
55
import java.util.Map;
66
import java.util.Optional;
7-
import java.util.stream.Collectors;
7+
8+
import jakarta.inject.Inject;
89

910
import org.jboss.logging.Logger;
1011
import org.kohsuke.github.GHEventPayload;
@@ -22,6 +23,7 @@
2223
import com.github.rvesse.airline.parser.ParseResult;
2324
import com.github.rvesse.airline.parser.errors.handlers.CollectAll;
2425

26+
import io.quarkiverse.githubapp.GitHubEvent;
2527
import io.quarkiverse.githubapp.command.airline.AirlineInject;
2628
import io.quarkiverse.githubapp.command.airline.CommandOptions.DefaultExecutionErrorHandlerMarker;
2729
import io.quarkiverse.githubapp.command.airline.ExecutionErrorHandler;
@@ -30,6 +32,9 @@
3032
import io.quarkiverse.githubapp.command.airline.ParseErrorHandler.ParseErrorContext;
3133
import io.quarkiverse.githubapp.command.airline.runtime.util.Commandline;
3234
import io.quarkiverse.githubapp.command.airline.runtime.util.Reactions;
35+
import io.quarkiverse.githubapp.runtime.telemetry.opentelemetry.OpenTelemetryAttributes.CommandErrorType;
36+
import io.quarkiverse.githubapp.telemetry.TelemetryMetricsReporter;
37+
import io.quarkiverse.githubapp.telemetry.TelemetryTracesReporter;
3338
import io.quarkus.arc.Arc;
3439
import io.quarkus.arc.InstanceHandle;
3540

@@ -43,6 +48,11 @@ public abstract class AbstractCommandDispatcher<C> {
4348
private final Map<String, CommandPermissionConfig> commandPermissionConfigs;
4449
private final Map<String, CommandTeamConfig> commandTeamConfigs;
4550

51+
@Inject
52+
TelemetryTracesReporter openTelemetryTracesReporter;
53+
@Inject
54+
TelemetryMetricsReporter openTelemetryMetricsReporter;
55+
4656
protected AbstractCommandDispatcher(Class<?> cliClass, CliConfig cliConfig) {
4757
ParserBuilder<C> parserBuilder = new ParserBuilder<C>();
4858
parserBuilder.withCommandFactory(new ArcCommandFactory<>());
@@ -62,7 +72,8 @@ protected AbstractCommandDispatcher(Class<?> cliClass, CliConfig cliConfig) {
6272

6373
protected abstract Map<String, CommandTeamConfig> getCommandTeamConfigs();
6474

65-
protected Optional<CommandExecutionContext<C>> getCommand(GHEventPayload.IssueComment issueCommentPayload) {
75+
protected Optional<CommandExecutionContext<C>> getCommand(GitHubEvent gitHubEvent,
76+
GHEventPayload.IssueComment issueCommentPayload) {
6677
String body = issueCommentPayload.getComment().getBody();
6778

6879
if (body == null || body.isBlank()) {
@@ -86,7 +97,7 @@ protected Optional<CommandExecutionContext<C>> getCommand(GHEventPayload.IssueCo
8697
commandLine = Commandline.translateCommandline(firstLine);
8798
commandLine.remove(0);
8899
} catch (IllegalArgumentException e) {
89-
handleParseError(issueCommentPayload, firstLine, null, e.getMessage());
100+
handleParseError(gitHubEvent, issueCommentPayload, firstLine, null, e.getMessage());
90101

91102
if (cliConfig.getDefaultCommandConfig().getReactionStrategy().reactionOnError()) {
92103
Reactions.createReaction(issueCommentPayload, ReactionContent.CONFUSED);
@@ -116,6 +127,10 @@ protected Optional<CommandExecutionContext<C>> getCommand(GHEventPayload.IssueCo
116127
if (commandConfig.getReactionStrategy().reactionOnError()) {
117128
Reactions.createReaction(issueCommentPayload, ReactionContent.MINUS_ONE);
118129
}
130+
openTelemetryTracesReporter.reportCommandMethodError(gitHubEvent, commandClassName, firstLine,
131+
CommandErrorType.PERMISSION_ERROR, null);
132+
openTelemetryMetricsReporter.incrementCommandMethodError(gitHubEvent, commandClassName,
133+
CommandErrorType.PERMISSION_ERROR, null);
119134
return Optional.empty();
120135
}
121136

@@ -134,7 +149,7 @@ protected Optional<CommandExecutionContext<C>> getCommand(GHEventPayload.IssueCo
134149
Reactions.createReaction(issueCommentPayload, ReactionContent.CONFUSED);
135150
}
136151

137-
handleParseError(issueCommentPayload, firstLine, parseResult, null);
152+
handleParseError(gitHubEvent, issueCommentPayload, firstLine, parseResult, null);
138153

139154
return Optional.empty();
140155
}
@@ -169,7 +184,7 @@ private boolean hasPermission(CommandPermissionConfig commandPermissionConfig,
169184

170185
List<GHTeam> matchingTeams = repository.getTeams().stream()
171186
.filter(t -> commandTeamConfig.getTeams().contains(t.getSlug()))
172-
.collect(Collectors.toList());
187+
.toList();
173188

174189
for (GHTeam matchingTeam : matchingTeams) {
175190
if (matchingTeam.hasMember(user)) {
@@ -195,7 +210,7 @@ private CommandConfig getBestCommandConfigInErrorState(ParseResult<C> parseResul
195210
cliConfig.getDefaultCommandConfig());
196211
}
197212

198-
protected void handleParseError(IssueComment issueCommentPayload, String command,
213+
protected void handleParseError(GitHubEvent gitHubEvent, IssueComment issueCommentPayload, String command,
199214
ParseResult<C> parseResult, String error) {
200215
Class<? extends ParseErrorHandler> parseErrorHandlerClass = cliConfig.getParseErrorHandler();
201216

@@ -209,9 +224,14 @@ protected void handleParseError(IssueComment issueCommentPayload, String command
209224
parseErrorHandlerInstance.get().handleParseError(issueCommentPayload,
210225
new ParseErrorContext(cliConfig, cli, command, parseResult, error));
211226
}
227+
228+
openTelemetryTracesReporter.reportCommandMethodError(gitHubEvent, null, command, CommandErrorType.PARSE_ERROR,
229+
error);
230+
openTelemetryMetricsReporter.incrementCommandMethodError(gitHubEvent, null, CommandErrorType.PARSE_ERROR,
231+
error);
212232
}
213233

214-
protected void handleExecutionError(GHEventPayload.IssueComment issueCommentPayload,
234+
protected void handleExecutionError(GitHubEvent gitHubEvent, GHEventPayload.IssueComment issueCommentPayload,
215235
CommandExecutionContext<C> commandExecutionContext, Exception exception) {
216236
Class<? extends ExecutionErrorHandler> executionErrorHandlerClass = commandExecutionContext.getCommandConfig()
217237
.getExecutionErrorHandler();
@@ -232,6 +252,21 @@ protected void handleExecutionError(GHEventPayload.IssueComment issueCommentPayl
232252
executionErrorHandlerInstance.get().handleExecutionError(issueCommentPayload,
233253
new ExecutionErrorContext(commandExecutionContext, exception));
234254
}
255+
256+
openTelemetryTracesReporter.reportCommandMethodError(gitHubEvent,
257+
commandExecutionContext.getCommand().getClass().getName(), commandExecutionContext.getCommandLine(),
258+
CommandErrorType.EXECUTION_ERROR, exception.getMessage());
259+
openTelemetryMetricsReporter.incrementCommandMethodError(gitHubEvent,
260+
commandExecutionContext.getCommand().getClass().getName(), CommandErrorType.EXECUTION_ERROR,
261+
exception.getMessage());
262+
}
263+
264+
protected void handleSuccess(GitHubEvent gitHubEvent, GHEventPayload.IssueComment issueCommentPayload,
265+
CommandExecutionContext<C> commandExecutionContext) {
266+
openTelemetryTracesReporter.reportCommandMethodSuccess(gitHubEvent,
267+
commandExecutionContext.getCommand().getClass().getName(), commandExecutionContext.getCommandLine());
268+
openTelemetryMetricsReporter.incrementCommandMethodSuccess(gitHubEvent,
269+
commandExecutionContext.getCommand().getClass().getName());
235270
}
236271

237272
public static class CommandExecutionContext<C> {
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package io.quarkiverse.githubapp.deployment;
2+
3+
import java.util.Optional;
4+
5+
import io.quarkus.runtime.annotations.ConfigDocSection;
6+
import io.quarkus.runtime.annotations.ConfigGroup;
7+
import io.quarkus.runtime.annotations.ConfigPhase;
8+
import io.quarkus.runtime.annotations.ConfigRoot;
9+
import io.smallrye.config.ConfigMapping;
10+
import io.smallrye.config.WithName;
11+
12+
@ConfigRoot(phase = ConfigPhase.BUILD_TIME)
13+
@ConfigMapping(prefix = "quarkus.github-app")
14+
public interface GitHubAppBuildTimeConfig {
15+
16+
/**
17+
* Telemetry configuration.
18+
*/
19+
@ConfigDocSection
20+
Telemetry telemetry();
21+
22+
@ConfigGroup
23+
interface Telemetry {
24+
25+
/**
26+
* Whether telemetry traces integration is active at runtime or not.
27+
* <p>
28+
* Defaults to true when the Quarkus OpenTelemetry integration is present and enabled.
29+
*/
30+
@WithName("traces.enabled")
31+
Optional<Boolean> tracesEnabled();
32+
33+
/**
34+
* Whether telemetry metrics integration is active at runtime or not.
35+
* <p>
36+
* Defaults to true when the Quarkus OpenTelemetry integration is present and enabled.
37+
*/
38+
@WithName("metrics.enabled")
39+
Optional<Boolean> metricsEnabled();
40+
}
41+
}

deployment/src/main/java/io/quarkiverse/githubapp/deployment/GitHubAppDotNames.java

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,26 @@
1111
import io.quarkiverse.githubapp.runtime.Multiplexer;
1212
import io.smallrye.graphql.client.dynamic.api.DynamicGraphQLClient;
1313

14-
final class GitHubAppDotNames {
14+
public final class GitHubAppDotNames {
1515

1616
static final DotName EVENT = DotName.createSimple(Event.class.getName());
1717
static final DotName RAW_EVENT = DotName.createSimple(RawEvent.class.getName());
1818
static final DotName CONFIG_FILE = DotName.createSimple(ConfigFile.class.getName());
1919
static final DotName MULTIPLEXER = DotName.createSimple(Multiplexer.class.getName());
2020
static final DotName ERROR_HANDLER = DotName.createSimple(ErrorHandler.class.getName());
2121

22-
static final DotName GITHUB = DotName.createSimple(GitHub.class.getName());
23-
static final DotName GITHUB_EVENT = DotName.createSimple(GitHubEvent.class.getName());
24-
static final DotName DYNAMIC_GRAPHQL_CLIENT = DotName.createSimple(DynamicGraphQLClient.class.getName());
22+
public static final DotName GITHUB = DotName.createSimple(GitHub.class.getName());
23+
public static final DotName GITHUB_EVENT = DotName.createSimple(GitHubEvent.class.getName());
24+
public static final DotName DYNAMIC_GRAPHQL_CLIENT = DotName.createSimple(DynamicGraphQLClient.class.getName());
25+
26+
static final DotName OPENTELEMETRY_TRACES_REPORTER = DotName
27+
.createSimple("io.quarkiverse.githubapp.runtime.telemetry.opentelemetry.OpenTelemetryTracesReporter");
28+
static final DotName OPENTELEMETRY_METRICS_REPORTER = DotName
29+
.createSimple("io.quarkiverse.githubapp.runtime.telemetry.opentelemetry.OpenTelemetryMetricsReporter");
30+
static final DotName OPENTELEMETRY_JAVA_HTTP_CLIENT_FACTORY = DotName
31+
.createSimple("io.quarkiverse.githubapp.runtime.telemetry.opentelemetry.OpenTelemetryJavaHttpClientFactory");
32+
static final DotName JAVA_HTTP_CLIENT_TELEMETRY = DotName
33+
.createSimple("io.opentelemetry.instrumentation.httpclient.JavaHttpClientTelemetry");
2534

2635
private GitHubAppDotNames() {
2736
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package io.quarkiverse.githubapp.deployment;
2+
3+
import io.quarkus.builder.item.SimpleBuildItem;
4+
5+
final class GitHubAppOpenTelemetryMetricsIntegrationEnabledBuildItem extends SimpleBuildItem {
6+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package io.quarkiverse.githubapp.deployment;
2+
3+
import io.quarkus.builder.item.SimpleBuildItem;
4+
5+
final class GitHubAppOpenTelemetryTracesIntegrationEnabledBuildItem extends SimpleBuildItem {
6+
}

0 commit comments

Comments
 (0)