From b780de94eb5196972fe3daac870dfec190bf5081 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Novotn=C3=BD?= Date: Fri, 19 Jul 2024 22:35:13 +0200 Subject: [PATCH] feat(#615): JFR recording API --- .../observability/annotation/EventGroup.java | 5 + .../evitadb/core/file/ExportFileService.java | 1 + .../event/cache/AbstractCacheEvent.java | 6 +- .../event/query/AbstractQueryEvent.java | 6 +- .../event/session/AbstractSessionEvent.java | 6 +- .../event/storage/AbstractStorageEvent.java | 6 +- .../event/system/AbstractSystemEvent.java | 6 +- .../transaction/AbstractTransactionEvent.java | 6 +- .../AbstractGraphQLInstanceEvent.java | 6 +- .../request/AbstractGraphQLRequestEvent.java | 6 +- .../metric/event/AbstractGrpcApiEvent.java | 6 +- .../observability/ObservabilityManager.java | 20 ++-- .../ObservabilityProviderRegistrar.java | 2 +- .../logging/JfrRecordingEndpointHandler.java | 4 +- .../metric/EvitaJfrEventRegistry.java | 41 +++++-- .../observability/task/JfrRecorderTask.java | 100 +++++++++--------- .../src/main/java/module-info.java | 1 + .../instance/AbstractRestInstanceEvent.java | 6 +- .../request/AbstractRestRequestEvent.java | 6 +- 19 files changed, 160 insertions(+), 80 deletions(-) diff --git a/evita_api/src/main/java/io/evitadb/api/observability/annotation/EventGroup.java b/evita_api/src/main/java/io/evitadb/api/observability/annotation/EventGroup.java index 72fb18c7b..b495b4edb 100644 --- a/evita_api/src/main/java/io/evitadb/api/observability/annotation/EventGroup.java +++ b/evita_api/src/main/java/io/evitadb/api/observability/annotation/EventGroup.java @@ -42,6 +42,11 @@ */ String value(); + /** + * Contains a human-readable name of the group. + */ + String name() default ""; + /** * Contains a description of the group. */ diff --git a/evita_engine/src/main/java/io/evitadb/core/file/ExportFileService.java b/evita_engine/src/main/java/io/evitadb/core/file/ExportFileService.java index 0e9fd78de..f94dd7e58 100644 --- a/evita_engine/src/main/java/io/evitadb/core/file/ExportFileService.java +++ b/evita_engine/src/main/java/io/evitadb/core/file/ExportFileService.java @@ -183,6 +183,7 @@ public FileForFetch createFile( "Failed to create file." ) ); + lock.lock(); try { final FileForFetch fileForFetch = new FileForFetch( fileId, diff --git a/evita_engine/src/main/java/io/evitadb/core/metric/event/cache/AbstractCacheEvent.java b/evita_engine/src/main/java/io/evitadb/core/metric/event/cache/AbstractCacheEvent.java index eb1f6049d..950bb5de1 100644 --- a/evita_engine/src/main/java/io/evitadb/core/metric/event/cache/AbstractCacheEvent.java +++ b/evita_engine/src/main/java/io/evitadb/core/metric/event/cache/AbstractCacheEvent.java @@ -32,7 +32,11 @@ /** * This event is base class for all cache related events. */ -@EventGroup(value = AbstractCacheEvent.PACKAGE_NAME, description = "evitaDB events relating to internal database cache.") +@EventGroup( + value = AbstractCacheEvent.PACKAGE_NAME, + name = "evitaDB - Cache", + description = "evitaDB events relating to internal database cache." +) @Category({"evitaDB", "Cache"}) @RequiredArgsConstructor @Getter diff --git a/evita_engine/src/main/java/io/evitadb/core/metric/event/query/AbstractQueryEvent.java b/evita_engine/src/main/java/io/evitadb/core/metric/event/query/AbstractQueryEvent.java index 7eca5a3be..5a4b9669f 100644 --- a/evita_engine/src/main/java/io/evitadb/core/metric/event/query/AbstractQueryEvent.java +++ b/evita_engine/src/main/java/io/evitadb/core/metric/event/query/AbstractQueryEvent.java @@ -35,7 +35,11 @@ /** * This event is base class for all query related events. */ -@EventGroup(value = AbstractQueryEvent.PACKAGE_NAME, description = "evitaDB events relating to query processing.") +@EventGroup( + value = AbstractQueryEvent.PACKAGE_NAME, + name = "evitaDB - Query", + description = "evitaDB events relating to query processing." +) @Category({"evitaDB", "Query"}) @RequiredArgsConstructor @Getter diff --git a/evita_engine/src/main/java/io/evitadb/core/metric/event/session/AbstractSessionEvent.java b/evita_engine/src/main/java/io/evitadb/core/metric/event/session/AbstractSessionEvent.java index 9f749c120..eb10a5c55 100644 --- a/evita_engine/src/main/java/io/evitadb/core/metric/event/session/AbstractSessionEvent.java +++ b/evita_engine/src/main/java/io/evitadb/core/metric/event/session/AbstractSessionEvent.java @@ -35,7 +35,11 @@ /** * This event is base class for all session related events. */ -@EventGroup(value = AbstractSessionEvent.PACKAGE_NAME, description = "evitaDB events relating to session handling.") +@EventGroup( + value = AbstractSessionEvent.PACKAGE_NAME, + name = "evitaDB - Session", + description = "evitaDB events relating to session handling." +) @Category({"evitaDB", "Session"}) @RequiredArgsConstructor @Getter diff --git a/evita_engine/src/main/java/io/evitadb/core/metric/event/storage/AbstractStorageEvent.java b/evita_engine/src/main/java/io/evitadb/core/metric/event/storage/AbstractStorageEvent.java index 9ac718037..c977cbbac 100644 --- a/evita_engine/src/main/java/io/evitadb/core/metric/event/storage/AbstractStorageEvent.java +++ b/evita_engine/src/main/java/io/evitadb/core/metric/event/storage/AbstractStorageEvent.java @@ -35,7 +35,11 @@ /** * This event is base class for all transaction events. */ -@EventGroup(value = AbstractStorageEvent.PACKAGE_NAME, description = "evitaDB events relating to data storage.") +@EventGroup( + value = AbstractStorageEvent.PACKAGE_NAME, + name = "evitaDB - Storage", + description = "evitaDB events relating to data storage." +) @Category({"evitaDB", "Storage"}) @RequiredArgsConstructor @Getter diff --git a/evita_engine/src/main/java/io/evitadb/core/metric/event/system/AbstractSystemEvent.java b/evita_engine/src/main/java/io/evitadb/core/metric/event/system/AbstractSystemEvent.java index 179a742ad..66666f043 100644 --- a/evita_engine/src/main/java/io/evitadb/core/metric/event/system/AbstractSystemEvent.java +++ b/evita_engine/src/main/java/io/evitadb/core/metric/event/system/AbstractSystemEvent.java @@ -32,7 +32,11 @@ /** * This event is base class for all system related events. */ -@EventGroup(value = AbstractSystemEvent.PACKAGE_NAME, description = "evitaDB events relating to system wide operations, such as tasks, threads etc.") +@EventGroup( + value = AbstractSystemEvent.PACKAGE_NAME, + name = "evitaDB - System", + description = "evitaDB events relating to system wide operations, such as tasks, threads etc." +) @Category({"evitaDB", "System"}) @RequiredArgsConstructor @Getter diff --git a/evita_engine/src/main/java/io/evitadb/core/metric/event/transaction/AbstractTransactionEvent.java b/evita_engine/src/main/java/io/evitadb/core/metric/event/transaction/AbstractTransactionEvent.java index d078b7a2c..1e67089e0 100644 --- a/evita_engine/src/main/java/io/evitadb/core/metric/event/transaction/AbstractTransactionEvent.java +++ b/evita_engine/src/main/java/io/evitadb/core/metric/event/transaction/AbstractTransactionEvent.java @@ -35,7 +35,11 @@ /** * This event is base class for all transaction events. */ -@EventGroup(value = AbstractTransactionEvent.PACKAGE_NAME, description = "evitaDB events relating to transaction processing.") +@EventGroup( + value = AbstractTransactionEvent.PACKAGE_NAME, + name = "evitaDB - Transaction", + description = "evitaDB events relating to transaction processing." +) @Category({"evitaDB", "Transaction"}) @RequiredArgsConstructor @Getter diff --git a/evita_external_api/evita_external_api_graphql/src/main/java/io/evitadb/externalApi/graphql/metric/event/instance/AbstractGraphQLInstanceEvent.java b/evita_external_api/evita_external_api_graphql/src/main/java/io/evitadb/externalApi/graphql/metric/event/instance/AbstractGraphQLInstanceEvent.java index d97fab496..afdc2091a 100644 --- a/evita_external_api/evita_external_api_graphql/src/main/java/io/evitadb/externalApi/graphql/metric/event/instance/AbstractGraphQLInstanceEvent.java +++ b/evita_external_api/evita_external_api_graphql/src/main/java/io/evitadb/externalApi/graphql/metric/event/instance/AbstractGraphQLInstanceEvent.java @@ -34,7 +34,11 @@ * * @author Lukáš Hornych, FG Forrest a.s. (c) 2024 */ -@EventGroup(value = AbstractGraphQLInstanceEvent.PACKAGE_NAME, description = "evitaDB events relating to GraphQL API.") +@EventGroup( + value = AbstractGraphQLInstanceEvent.PACKAGE_NAME, + name = "evitaDB - GraphQL API", + description = "evitaDB events relating to GraphQL API." +) @Category({"evitaDB", "API", "GraphQL", "Instance", "Schema"}) @RequiredArgsConstructor @Getter diff --git a/evita_external_api/evita_external_api_graphql/src/main/java/io/evitadb/externalApi/graphql/metric/event/request/AbstractGraphQLRequestEvent.java b/evita_external_api/evita_external_api_graphql/src/main/java/io/evitadb/externalApi/graphql/metric/event/request/AbstractGraphQLRequestEvent.java index 17495b9a9..f186d36d1 100644 --- a/evita_external_api/evita_external_api_graphql/src/main/java/io/evitadb/externalApi/graphql/metric/event/request/AbstractGraphQLRequestEvent.java +++ b/evita_external_api/evita_external_api_graphql/src/main/java/io/evitadb/externalApi/graphql/metric/event/request/AbstractGraphQLRequestEvent.java @@ -39,7 +39,11 @@ * * @author Lukáš Hornych, FG Forrest a.s. (c) 2024 */ -@EventGroup(value = AbstractGraphQLRequestEvent.PACKAGE_NAME, description = "evitaDB events relating to GraphQL request processing.") +@EventGroup( + value = AbstractGraphQLRequestEvent.PACKAGE_NAME, + name = "evitaDB - GraphQL Request", + description = "evitaDB events relating to GraphQL request processing." +) @Category({"evitaDB", "ExternalAPI", "GraphQL", "Request"}) @Getter public class AbstractGraphQLRequestEvent extends CustomMetricsExecutionEvent { diff --git a/evita_external_api/evita_external_api_grpc/server/src/main/java/io/evitadb/externalApi/grpc/metric/event/AbstractGrpcApiEvent.java b/evita_external_api/evita_external_api_grpc/server/src/main/java/io/evitadb/externalApi/grpc/metric/event/AbstractGrpcApiEvent.java index 83ef78c11..f2b8d3c6a 100644 --- a/evita_external_api/evita_external_api_grpc/server/src/main/java/io/evitadb/externalApi/grpc/metric/event/AbstractGrpcApiEvent.java +++ b/evita_external_api/evita_external_api_grpc/server/src/main/java/io/evitadb/externalApi/grpc/metric/event/AbstractGrpcApiEvent.java @@ -35,7 +35,11 @@ /** * This event is base class for all gRPC API related events. */ -@EventGroup(value = AbstractGrpcApiEvent.PACKAGE_NAME, description = "evitaDB events relating to gRPC request processing.") +@EventGroup( + value = AbstractGrpcApiEvent.PACKAGE_NAME, + name = "evitaDB - gRPC Request", + description = "evitaDB events relating to gRPC request processing." +) @Category({"evitaDB", "API", "gRPC"}) @RequiredArgsConstructor @Getter diff --git a/evita_external_api/evita_external_api_observability/src/main/java/io/evitadb/externalApi/observability/ObservabilityManager.java b/evita_external_api/evita_external_api_observability/src/main/java/io/evitadb/externalApi/observability/ObservabilityManager.java index 354a13eb7..58f0bc088 100644 --- a/evita_external_api/evita_external_api_observability/src/main/java/io/evitadb/externalApi/observability/ObservabilityManager.java +++ b/evita_external_api/evita_external_api_observability/src/main/java/io/evitadb/externalApi/observability/ObservabilityManager.java @@ -24,6 +24,7 @@ package io.evitadb.externalApi.observability; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import com.linecorp.armeria.server.HttpService; import com.linecorp.armeria.server.file.FileService; import io.evitadb.api.exception.SingletonTaskAlreadyRunningException; @@ -34,7 +35,6 @@ import io.evitadb.core.metric.event.CustomMetricsExecutionEvent; import io.evitadb.exception.EvitaInvalidUsageException; import io.evitadb.exception.UnexpectedIOException; -import io.evitadb.externalApi.configuration.ApiOptions; import io.evitadb.externalApi.http.CorsEndpoint; import io.evitadb.externalApi.http.ExternalApiProviderRegistrar; import io.evitadb.externalApi.observability.agent.ErrorMonitor; @@ -120,10 +120,6 @@ public class ObservabilityManager { * Observability API config. */ private final ObservabilityConfig config; - /** - * API options part of the config. - */ - private final ApiOptions apiOptions; /** * Evita instance. */ @@ -131,7 +127,7 @@ public class ObservabilityManager { /** * Common object mapper for endpoints */ - @Nonnull @Getter private final ObjectMapper objectMapper = new ObjectMapper(); + @Nonnull @Getter private final ObjectMapper objectMapper; static { ClassLoader classLoader = null; @@ -174,13 +170,14 @@ public static void evitaErrorEvent(@Nonnull String simpleName) { } } - public ObservabilityManager(ObservabilityConfig config, ApiOptions apiOptions, Evita evita) { + public ObservabilityManager(ObservabilityConfig config, Evita evita) { this.config = config; - this.apiOptions = apiOptions; this.evita = evita; createAndRegisterPrometheusServlet(); registerJfrControlEndpoints(); registerRecordingFileResourceHandler(); + objectMapper = new ObjectMapper(); + objectMapper.registerModule(new JavaTimeModule()); } /** @@ -242,16 +239,16 @@ public void clearHealthProblem(@Nonnull String healthProblem) { @Nonnull public List getAvailableJfrEventTypes() { return Stream.concat( - EvitaJfrEventRegistry.getCustomEventPackages() + EvitaJfrEventRegistry.getEvitaEventGroups() .values() .stream() .sorted(Comparator.comparing(EvitaEventGroup::name)) - .map(it -> new RecordingGroup(it.name(), it.description())), + .map(it -> new RecordingGroup(it.id(), it.name(), it.description())), EvitaJfrEventRegistry.getJdkEventGroups() .values() .stream() .sorted(Comparator.comparing(JdkEventGroup::name)) - .map(it -> new RecordingGroup(it.name(), it.description())) + .map(it -> new RecordingGroup(it.id(), it.name(), it.description())) ) .toList(); } @@ -393,6 +390,7 @@ private void registerJfrControlEndpoints() { * @param description the description of the group */ public record RecordingGroup( + @Nonnull String id, @Nonnull String name, @Nullable String description ) { diff --git a/evita_external_api/evita_external_api_observability/src/main/java/io/evitadb/externalApi/observability/ObservabilityProviderRegistrar.java b/evita_external_api/evita_external_api_observability/src/main/java/io/evitadb/externalApi/observability/ObservabilityProviderRegistrar.java index c3e37b267..5289d2e1a 100644 --- a/evita_external_api/evita_external_api_observability/src/main/java/io/evitadb/externalApi/observability/ObservabilityProviderRegistrar.java +++ b/evita_external_api/evita_external_api_observability/src/main/java/io/evitadb/externalApi/observability/ObservabilityProviderRegistrar.java @@ -64,7 +64,7 @@ public int getOrder() { @Nonnull @Override public ExternalApiProvider register(@Nonnull Evita evita, @Nonnull ExternalApiServer externalApiServer, @Nonnull ApiOptions apiOptions, @Nonnull ObservabilityConfig observabilityConfig) { - final ObservabilityManager observabilityManager = new ObservabilityManager(observabilityConfig, apiOptions, evita); + final ObservabilityManager observabilityManager = new ObservabilityManager(observabilityConfig, evita); final TracingConfig tracingConfig = observabilityConfig.getTracing(); if (tracingConfig != null && tracingConfig.getEndpoint() != null) { OpenTelemetryTracerSetup.setTracingConfig(observabilityConfig.getTracing()); diff --git a/evita_external_api/evita_external_api_observability/src/main/java/io/evitadb/externalApi/observability/logging/JfrRecordingEndpointHandler.java b/evita_external_api/evita_external_api_observability/src/main/java/io/evitadb/externalApi/observability/logging/JfrRecordingEndpointHandler.java index d3a4b6d72..fc15e021f 100644 --- a/evita_external_api/evita_external_api_observability/src/main/java/io/evitadb/externalApi/observability/logging/JfrRecordingEndpointHandler.java +++ b/evita_external_api/evita_external_api_observability/src/main/java/io/evitadb/externalApi/observability/logging/JfrRecordingEndpointHandler.java @@ -115,7 +115,9 @@ protected void writeResponse(@Nonnull JfrRecordingEndpointExecutionContext execu responseWriter.write(HttpData.ofUtf8(manager.getObjectMapper().writeValueAsString(result))); } catch (JsonProcessingException e) { throw new GenericEvitaInternalError( - "Failed to serialize available JFR event types", + "Failed to serialize response object to JSON.", + "Failed to serialize response object to JSON: " + e.getMessage(), + e ); } diff --git a/evita_external_api/evita_external_api_observability/src/main/java/io/evitadb/externalApi/observability/metric/EvitaJfrEventRegistry.java b/evita_external_api/evita_external_api_observability/src/main/java/io/evitadb/externalApi/observability/metric/EvitaJfrEventRegistry.java index 28484e983..f9feb0c59 100644 --- a/evita_external_api/evita_external_api_observability/src/main/java/io/evitadb/externalApi/observability/metric/EvitaJfrEventRegistry.java +++ b/evita_external_api/evita_external_api_observability/src/main/java/io/evitadb/externalApi/observability/metric/EvitaJfrEventRegistry.java @@ -145,6 +145,7 @@ public class EvitaJfrEventRegistry { "Security", new JdkEventGroup( "Security", + "JDK - Security", "Events related to security and cryptography.", new String[]{ "jdk.X509Validation", @@ -159,6 +160,7 @@ public class EvitaJfrEventRegistry { "ProcessAndContainerManagement", new JdkEventGroup( "ProcessAndContainerManagement", + "JDK - Process and container management", "Events related to process and container management.", new String[]{ "jdk.ProcessStart", @@ -175,6 +177,7 @@ public class EvitaJfrEventRegistry { "ThreadManagement", new JdkEventGroup( "ThreadManagement", + "JDK - Thread management", "Events related to thread management.", new String[]{ "jdk.ThreadStart", @@ -192,6 +195,7 @@ public class EvitaJfrEventRegistry { "GarbageCollection", new JdkEventGroup( "GarbageCollection", + "JDK - Garbage collection", "Events related to garbage collection.", new String[]{ "jdk.GCHeapSummary", @@ -257,6 +261,7 @@ public class EvitaJfrEventRegistry { "FileOperations", new JdkEventGroup( "FileOperations", + "JDK - File operations", "Events related to file operations.", new String[]{ "jdk.SocketWrite", @@ -273,6 +278,7 @@ public class EvitaJfrEventRegistry { "ExceptionsAndErrors", new JdkEventGroup( "ExceptionsAndErrors", + "JDK - Exceptions and errors", "Events related to exception handling and errors.", new String[]{ "jdk.JavaErrorThrow", @@ -288,6 +294,7 @@ public class EvitaJfrEventRegistry { "ClassLoadingAndModification", new JdkEventGroup( "ClassLoadingAndModification", + "JDK - Class loading and modification", "Events related to class loading and modification.", new String[]{ "jdk.ClassLoad", @@ -306,6 +313,7 @@ public class EvitaJfrEventRegistry { "SystemAndJVMInfo", new JdkEventGroup( "SystemAndJVMInfo", + "JDK - System and JVM information", "Events related to system and JVM information.", new String[]{ "jdk.JVMInformation", @@ -329,6 +337,7 @@ public class EvitaJfrEventRegistry { "MemoryAllocation", new JdkEventGroup( "MemoryAllocation", + "JDK - Memory allocation", "Events related to memory allocation.", new String[]{ "jdk.ObjectAllocationInNewTLAB", @@ -344,6 +353,7 @@ public class EvitaJfrEventRegistry { "MonitoringAndStatistics", new JdkEventGroup( "MonitoringAndStatistics", + "JDK - Monitoring and statistics", "Events related to monitoring and statistics.", new String[]{ "jdk.ActiveRecording", @@ -381,6 +391,7 @@ public class EvitaJfrEventRegistry { "CompilationAndOptimization", new JdkEventGroup( "CompilationAndOptimization", + "JDK - Compilation and optimization", "Events related to compilation and optimization.", new String[]{ "jdk.Compilation", @@ -405,6 +416,7 @@ public class EvitaJfrEventRegistry { "Safepoints", new JdkEventGroup( "Safepoints", + "JDK - Safepoints", "Events related to safe points.", new String[]{ "jdk.SafepointBegin", @@ -420,6 +432,7 @@ public class EvitaJfrEventRegistry { "Flags", new JdkEventGroup( "Flags", + "JDK - Flags", "Events related to flags.", new String[]{ "jdk.IntFlag", @@ -437,6 +450,7 @@ public class EvitaJfrEventRegistry { "FlushingAndCleaningUp", new JdkEventGroup( "FlushingAndCleaningUp", + "JDK - Flushing and cleaning up", "Events related to flushing and cleaning up.", new String[]{ "jdk.Flush", @@ -457,6 +471,7 @@ public class EvitaJfrEventRegistry { "Other", new JdkEventGroup( "Other", + "JDK - Other", "Other JDK events, that were not categorized.", unknownJdkEvents ) @@ -475,11 +490,13 @@ public class EvitaJfrEventRegistry { Collectors.collectingAndThen( Collectors.toSet(), events -> { - String groupName = EvitaJfrEventRegistry.getMetricsGroup(events.iterator().next()); - EventGroup groupInfo = KNOWN_EVITA_GROUPS.get(groupName); + EventGroup groupInfo = KNOWN_EVITA_GROUPS.get( + EvitaJfrEventRegistry.getMetricsGroup(events.iterator().next()) + ); //noinspection unchecked return new EvitaEventGroup( - groupName, + groupInfo.value(), + groupInfo.name(), groupInfo.description(), events.toArray(new Class[0]) ); @@ -537,7 +554,7 @@ public static Set> getEventClasses( * @return a map of all registered event packages fetched from the registry */ @Nonnull - public static Map getCustomEventPackages() { + public static Map getEvitaEventGroups() { return EVENT_MAP_BY_PACKAGE; } @@ -559,15 +576,25 @@ public static Map getJdkEventGroups() { * @param events the names of the events in the group */ public record EvitaEventGroup( + @Nonnull String id, @Nonnull String name, @Nullable String description, @Nonnull Class[] events ) { - public EvitaEventGroup(@Nonnull String name, @Nullable String description, @Nonnull Class[] events) { + public EvitaEventGroup( + @Nonnull String id, + @Nonnull String name, + @Nullable String description, + @Nonnull Class[] events + ) { + this.id = id; this.name = name; this.description = description; this.events = events; + for (Class event : events) { + FlightRecorder.register(event); + } } } @@ -579,12 +606,14 @@ public EvitaEventGroup(@Nonnull String name, @Nullable String description, @Nonn * @param events the names of the events in the group */ public record JdkEventGroup( + @Nonnull String id, @Nonnull String name, @Nullable String description, @Nonnull String[] events ) { - public JdkEventGroup(@Nonnull String name, @Nullable String description, @Nonnull String[] events) { + public JdkEventGroup(@Nonnull String id, @Nonnull String name, @Nullable String description, @Nonnull String[] events) { + this.id = id; this.name = name; this.description = description; this.events = events; diff --git a/evita_external_api/evita_external_api_observability/src/main/java/io/evitadb/externalApi/observability/task/JfrRecorderTask.java b/evita_external_api/evita_external_api_observability/src/main/java/io/evitadb/externalApi/observability/task/JfrRecorderTask.java index 6bf7d4a75..2e46049c9 100644 --- a/evita_external_api/evita_external_api_observability/src/main/java/io/evitadb/externalApi/observability/task/JfrRecorderTask.java +++ b/evita_external_api/evita_external_api_observability/src/main/java/io/evitadb/externalApi/observability/task/JfrRecorderTask.java @@ -26,9 +26,10 @@ import io.evitadb.api.file.FileForFetch; import io.evitadb.core.async.ClientCallableTask; import io.evitadb.core.file.ExportFileService; -import io.evitadb.core.metric.event.CustomMetricsExecutionEvent; import io.evitadb.externalApi.observability.exception.JfRException; import io.evitadb.externalApi.observability.metric.EvitaJfrEventRegistry; +import io.evitadb.externalApi.observability.metric.EvitaJfrEventRegistry.EvitaEventGroup; +import io.evitadb.externalApi.observability.metric.EvitaJfrEventRegistry.JdkEventGroup; import io.evitadb.externalApi.observability.task.JfrRecorderTask.RecordingSettings; import jdk.jfr.EventType; import jdk.jfr.FlightRecorder; @@ -39,13 +40,17 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.io.IOException; -import java.lang.reflect.Modifier; import java.nio.file.Path; import java.time.Duration; import java.time.OffsetDateTime; import java.time.format.DateTimeFormatter; import java.util.Arrays; -import java.util.List; +import java.util.HashSet; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; import static java.util.Optional.ofNullable; @@ -69,29 +74,6 @@ public class JfrRecorderTask extends ClientCallableTask !x.startsWith("jdk.")).toList()) { - if (event.endsWith(".*")) { - EvitaJfrEventRegistry.getEventClassesFromPackage(event) - .ifPresent(classes -> { - for (Class clazz : classes) { - if (!Modifier.isAbstract(clazz.getModifiers())) { - FlightRecorder.register(clazz); - } - } - }); - } else { - final Class clazz = EvitaJfrEventRegistry.getEventClass(event); - if (!Modifier.isAbstract(clazz.getModifiers())) { - FlightRecorder.register(clazz); - } - } - } - } - public JfrRecorderTask( @Nonnull String[] allowedEvents, @Nullable Long maxSizeInBytes, @@ -119,15 +101,6 @@ public boolean cancel() { return super.cancel(); } - /** - * Returns the name of the file that will be produced by this task. - * @return Name of the file. - */ - @Nonnull - public String getFileName() { - return this.targetFile.name(); - } - /** * Starts the JFR recording. * @return File where the recording will be stored. @@ -140,21 +113,14 @@ private FileForFetch start() { final RecordingSettings settings = getStatus().settings(); ofNullable(settings.maxSizeInBytes()).ifPresent(this.recording::setMaxSize); ofNullable(settings.maxAgeInSeconds()).map(Duration::ofSeconds).ifPresent(this.recording::setMaxAge); - final String[] allowedEvents = settings.allowedEvents(); - registerJfrEvents(allowedEvents); - final List eventTypes = FlightRecorder.getFlightRecorder().getEventTypes(); - for (String event : allowedEvents) { - if (event.endsWith(".*")) { - for (EventType eventType : eventTypes) { - String it = eventType.getName(); - if (it.startsWith(event.substring(0, event.length() - 2))) { - recording.enable(it).withoutThreshold(); - } - } - } else { - recording.enable(event).withoutThreshold(); - } - } + final Set allowedEvents = new HashSet<>(Arrays.asList(settings.allowedEvents())); + + // first disable all JDK events, that are not wanted + disableUnwantedJdkEvents(allowedEvents); + + // then register all custom event groups + enableEvitaEvents(allowedEvents); + this.recording.start(); return this.targetFile; } catch (IOException e) { @@ -162,6 +128,40 @@ private FileForFetch start() { } } + /** + * Disables all JDK events that are not in the allowed set. + * @param allowedEvents set of allowed events + */ + private void disableUnwantedJdkEvents(@Nonnull Set allowedEvents) { + final Set disabledJdkEvents = EvitaJfrEventRegistry.getJdkEventGroups() + .entrySet() + .stream() + .filter(entry -> !allowedEvents.contains(entry.getKey())) + .map(Entry::getValue) + .map(JdkEventGroup::events) + .flatMap(Arrays::stream) + .collect(Collectors.toSet()); + for (EventType eventType : FlightRecorder.getFlightRecorder().getEventTypes()) { + if (disabledJdkEvents.contains(eventType.getName())) { + this.recording.disable(eventType.getName()); + } + } + } + + /** + * Enables all Evita events that are in the allowed set. + * @param allowedEvents set of allowed events + */ + private void enableEvitaEvents(@Nonnull Set allowedEvents) { + final Map evitaEventGroups = EvitaJfrEventRegistry.getEvitaEventGroups(); + allowedEvents.stream() + .map(evitaEventGroups::get) + .filter(Objects::nonNull) + .map(EvitaEventGroup::events) + .flatMap(Arrays::stream) + .forEach(eventType -> recording.enable(eventType).withoutThreshold()); + } + /** * Stops the JFR recording. * @return File where the recording was stored. diff --git a/evita_external_api/evita_external_api_observability/src/main/java/module-info.java b/evita_external_api/evita_external_api_observability/src/main/java/module-info.java index 0bbb378d8..491d050f5 100644 --- a/evita_external_api/evita_external_api_observability/src/main/java/module-info.java +++ b/evita_external_api/evita_external_api_observability/src/main/java/module-info.java @@ -87,6 +87,7 @@ requires org.reactivestreams; requires io.prometheus.metrics.exporter.common; requires io.netty.transport; + requires com.fasterxml.jackson.datatype.jsr310; exports io.evitadb.externalApi.observability.configuration; exports io.evitadb.externalApi.observability.trace; diff --git a/evita_external_api/evita_external_api_rest/src/main/java/io/evitadb/externalApi/rest/metric/event/instance/AbstractRestInstanceEvent.java b/evita_external_api/evita_external_api_rest/src/main/java/io/evitadb/externalApi/rest/metric/event/instance/AbstractRestInstanceEvent.java index 177270579..007170d75 100644 --- a/evita_external_api/evita_external_api_rest/src/main/java/io/evitadb/externalApi/rest/metric/event/instance/AbstractRestInstanceEvent.java +++ b/evita_external_api/evita_external_api_rest/src/main/java/io/evitadb/externalApi/rest/metric/event/instance/AbstractRestInstanceEvent.java @@ -34,7 +34,11 @@ * * @author Lukáš Hornych, FG Forrest a.s. (c) 2024 */ -@EventGroup(value = AbstractRestInstanceEvent.PACKAGE_NAME, description = "evitaDB events relating to REST API.") +@EventGroup( + value = AbstractRestInstanceEvent.PACKAGE_NAME, + name = "evitaDB - REST API", + description = "evitaDB events relating to REST API." +) @Category({"evitaDB", "ExternalAPI", "REST", "Instance", "Schema"}) @RequiredArgsConstructor @Getter diff --git a/evita_external_api/evita_external_api_rest/src/main/java/io/evitadb/externalApi/rest/metric/event/request/AbstractRestRequestEvent.java b/evita_external_api/evita_external_api_rest/src/main/java/io/evitadb/externalApi/rest/metric/event/request/AbstractRestRequestEvent.java index 94e1a7d17..f2f17b7eb 100644 --- a/evita_external_api/evita_external_api_rest/src/main/java/io/evitadb/externalApi/rest/metric/event/request/AbstractRestRequestEvent.java +++ b/evita_external_api/evita_external_api_rest/src/main/java/io/evitadb/externalApi/rest/metric/event/request/AbstractRestRequestEvent.java @@ -40,7 +40,11 @@ * * @author Lukáš Hornych, FG Forrest a.s. (c) 2024 */ -@EventGroup(value = AbstractRestRequestEvent.PACKAGE_NAME, description = "evitaDB events relating to REST request processing.") +@EventGroup( + value = AbstractRestRequestEvent.PACKAGE_NAME, + name = "evitaDB - REST Request", + description = "evitaDB events relating to REST request processing." +) @Category({"evitaDB", "ExternalAPI", "REST", "Request"}) @Getter public class AbstractRestRequestEvent extends CustomMetricsExecutionEvent {