Skip to content

feat(reports): implement report request filtering, config default filter #880

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions schema/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,14 @@ components:
useRethrow:
type: boolean
type: object
EventAvailability:
enum:
- AVAILABLE
- ENABLED
- DISABLED
- NONE
- UNKNOWN
type: string
Field:
properties:
contentType:
Expand Down Expand Up @@ -479,6 +487,19 @@ components:
- STOPPED
- CLOSED
type: string
ReportRule:
properties:
id:
type: string
name:
type: string
requiredEvents:
additionalProperties:
$ref: '#/components/schemas/EventAvailability'
type: object
topic:
type: string
type: object
RequestData:
properties:
matchExpression:
Expand Down Expand Up @@ -874,6 +895,25 @@ paths:
- SecurityScheme: []
tags:
- Analysis Report Aggregator
/api/v4.1/reports_rules:
get:
responses:
"200":
content:
application/json:
schema:
items:
$ref: '#/components/schemas/ReportRule'
type: array
description: OK
"401":
description: Not Authorized
"403":
description: Not Allowed
security:
- SecurityScheme: []
tags:
- Reports
/api/v4.1/targets/{targetId}/reports:
get:
parameters:
Expand Down Expand Up @@ -1621,6 +1661,11 @@ paths:
required: true
schema:
type: string
- in: query
name: filter
schema:
default: ""
type: string
requestBody:
content:
application/json:
Expand Down Expand Up @@ -2365,6 +2410,11 @@ paths:
schema:
format: int64
type: integer
- in: query
name: filter
schema:
default: ""
type: string
requestBody:
content:
application/json:
Expand Down
13 changes: 12 additions & 1 deletion schema/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ type Target {
mbeanMetrics: MBeanMetrics
"Get the active and archived recordings belonging to this target"
recordings: Recordings
report: Report
report(filter: ReportFilterInput): Report
}

type ThreadMetrics {
Expand Down Expand Up @@ -341,3 +341,14 @@ input RecordingSettingsInput {
templateType: String!
toDisk: Boolean
}

input ReportFilterInput {
id: String
ids: [String]
notId: String
notIds: [String]
notTopic: String
notTopics: [String]
topic: String
topics: [String]
}
1 change: 1 addition & 0 deletions src/main/java/io/cryostat/ConfigProperties.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public class ConfigProperties {
public static final String CONNECTIONS_FAILED_TIMEOUT = "cryostat.connections.failed-timeout";
public static final String CONNECTIONS_UPLOAD_TIMEOUT = "cryostat.connections.upload-timeout";

public static final String REPORTS_FILTER = "cryostat.services.reports.filter";
public static final String REPORTS_SIDECAR_URL = "quarkus.rest-client.reports.url";
public static final String REPORTS_USE_PRESIGNED_TRANSFER =
"cryostat.services.reports.use-presigned-transfer";
Expand Down
8 changes: 8 additions & 0 deletions src/main/java/io/cryostat/Producers.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.util.concurrent.ForkJoinPool;

import io.cryostat.core.reports.InterruptibleReportGenerator;
import io.cryostat.core.util.RuleFilterParser;
import io.cryostat.libcryostat.sys.Clock;
import io.cryostat.libcryostat.sys.FileSystem;
import io.cryostat.recordings.LongRunningRequestGenerator;
Expand Down Expand Up @@ -77,6 +78,13 @@ public static InterruptibleReportGenerator produceInterruptibleReportGenerator()
singleThread ? Executors.newSingleThreadExecutor() : ForkJoinPool.commonPool());
}

@Produces
@ApplicationScoped
@DefaultBean
public static RuleFilterParser produceRuleFilterParser() {
return new RuleFilterParser();
}

@Produces
@RequestScoped
@DefaultBean
Expand Down
61 changes: 59 additions & 2 deletions src/main/java/io/cryostat/graphql/TargetNodes.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import org.openjdk.jmc.flightrecorder.rules.Severity;
Expand Down Expand Up @@ -107,7 +109,7 @@ public ArchivedRecordings archivedRecordings(
return recordings;
}

public Uni<Report> report(@Source Target target) {
public Uni<Report> report(@Source Target target, @Nullable ReportFilter filter) {
var fTarget = Target.getTargetById(target.id);
return reportAggregator
.getEntry(fTarget.jvmId)
Expand All @@ -116,7 +118,14 @@ public Uni<Report> report(@Source Target target) {
e -> {
var report = new Report();
report.lastUpdated = e.timestamp();
report.data = e.report();
report.data =
e.report().entrySet().stream()
.filter(r -> filter == null || filter.test(r))
.collect(
Collectors.toMap(
Entry<String, AnalysisResult>::getKey,
Entry<String, AnalysisResult>
::getValue));
report.aggregate = ReportAggregateInfo.from(report.data);
return report;
})
Expand Down Expand Up @@ -239,4 +248,52 @@ public static ReportAggregateInfo from(Map<String, AnalysisResult> report) {
.orElse(Severity.NA.getLimit()));
}
}

@SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
public static class ReportFilter implements Predicate<Map.Entry<String, AnalysisResult>> {
public @Nullable String id;
public @Nullable List<String> ids;
public @Nullable String notId;
public @Nullable List<String> notIds;
public @Nullable String topic;
public @Nullable List<String> topics;
public @Nullable String notTopic;
public @Nullable List<String> notTopics;

@Override
public boolean test(Map.Entry<String, AnalysisResult> e) {
Predicate<Map.Entry<String, AnalysisResult>> matchesId =
r -> id == null || Objects.equals(id, r.getKey());
Predicate<Map.Entry<String, AnalysisResult>> matchesIds =
r -> ids == null || ids.contains(r.getKey());

Predicate<Map.Entry<String, AnalysisResult>> matchesNotId =
r -> notId == null || !Objects.equals(notId, r.getKey());
Predicate<Map.Entry<String, AnalysisResult>> matchesNotIds =
r -> notIds == null || !notIds.contains(r.getKey());

Predicate<Map.Entry<String, AnalysisResult>> matchesTopic =
r -> topic == null || Objects.equals(topic, r.getValue().getTopic());
Predicate<Map.Entry<String, AnalysisResult>> matchesTopics =
r -> topics == null || topics.contains(r.getValue().getTopic());

Predicate<Map.Entry<String, AnalysisResult>> matchesNotTopic =
r -> notTopic == null || !Objects.equals(notTopic, r.getValue().getTopic());
Predicate<Map.Entry<String, AnalysisResult>> matchesNotTopics =
r -> notTopics == null || !notTopics.contains(r.getValue().getTopic());

return List.of(
matchesId,
matchesIds,
matchesNotId,
matchesNotIds,
matchesTopic,
matchesTopics,
matchesNotTopic,
matchesNotTopics)
.stream()
.reduce(x -> true, Predicate::and)
.test(e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ public Uni<Void> onMessage(GrafanaActiveUploadRequest request) {
public Uni<Map<String, AnalysisResult>> onMessage(ActiveReportRequest request) {
logger.trace("Job ID: " + request.id() + " submitted.");
return reportsService
.reportFor(request.recording)
.reportFor(request.recording, request.filter)
.onItem()
.invoke(
(report) -> {
Expand Down Expand Up @@ -234,7 +234,7 @@ public Uni<Map<String, AnalysisResult>> onMessage(ActiveReportRequest request) {
public Uni<Map<String, AnalysisResult>> onMessage(ArchivedReportRequest request) {
logger.tracev("Job ID: {0} submitted.", request.id());
return reportsService
.reportFor(request.pair().getKey(), request.pair().getValue())
.reportFor(request.pair().getKey(), request.pair().getValue(), request.filter)
.onItem()
.invoke(
(report) -> {
Expand Down Expand Up @@ -304,11 +304,15 @@ public record GrafanaActiveUploadRequest(String id, long remoteId, long targetId
// of the record. It shouldn't be a problem and we do similar things
// elswhere with other records.
@SuppressFBWarnings(value = {"EI_EXPOSE_REP", "EI_EXPOSE_REP2"})
public record ActiveReportRequest(String id, ActiveRecording recording) {
public record ActiveReportRequest(String id, ActiveRecording recording, String filter) {
public ActiveReportRequest {
Objects.requireNonNull(id);
Objects.requireNonNull(recording);
}

public ActiveReportRequest(String id, ActiveRecording recording) {
this(id, recording, null);
}
}

@SuppressFBWarnings(value = {"EI_EXPOSE_REP", "EI_EXPOSE_REP2"})
Expand All @@ -321,11 +325,15 @@ public record ActiveReportCompletion(
}
}

public record ArchivedReportRequest(String id, Pair<String, String> pair) {
public record ArchivedReportRequest(String id, Pair<String, String> pair, String filter) {
public ArchivedReportRequest {
Objects.requireNonNull(id);
Objects.requireNonNull(pair);
}

public ArchivedReportRequest(String id, Pair<String, String> pair) {
this(id, pair, null);
}
}

@SuppressFBWarnings(value = {"EI_EXPOSE_REP", "EI_EXPOSE_REP2"})
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/io/cryostat/recordings/RecordingHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -1303,7 +1303,7 @@ private Uni<String> uploadToJFRDatasource(Path recordingPath)
});
}

Optional<Path> getRecordingCopyPath(
private Optional<Path> getRecordingCopyPath(
JFRConnection connection, Target target, String recordingName) throws Exception {
return connection.getService().getAvailableRecordings().stream()
.filter(recording -> recording.getName().equals(recordingName))
Expand Down
20 changes: 8 additions & 12 deletions src/main/java/io/cryostat/reports/MemoryCachingReportsService.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,6 @@
package io.cryostat.reports;

import java.util.Map;
import java.util.function.Predicate;

import org.openjdk.jmc.flightrecorder.rules.IRule;

import io.cryostat.ConfigProperties;
import io.cryostat.core.reports.InterruptibleReportGenerator.AnalysisResult;
Expand Down Expand Up @@ -67,47 +64,46 @@ class MemoryCachingReportsService implements ReportsService {
@Inject Logger logger;

@Override
public Uni<Map<String, AnalysisResult>> reportFor(
ActiveRecording recording, Predicate<IRule> predicate) {
public Uni<Map<String, AnalysisResult>> reportFor(ActiveRecording recording, String filter) {
if (!quarkusCache || !memoryCache) {
logger.trace("cache disabled, delegating...");
return delegate.reportFor(recording, predicate);
return delegate.reportFor(recording, filter);
}
String key = ReportsService.key(recording);
logger.tracev("reportFor {0}", key);
return activeCache.getAsync(
key,
k -> {
logger.tracev("reportFor {0} cache miss", k);
return delegate.reportFor(recording);
return delegate.reportFor(recording, filter);
});
}

@Override
public Uni<Map<String, AnalysisResult>> reportFor(
String jvmId, String filename, Predicate<IRule> predicate) {
String jvmId, String filename, String filter) {
if (!quarkusCache || !memoryCache) {
logger.trace("cache disabled, delegating...");
return delegate.reportFor(jvmId, filename, predicate);
return delegate.reportFor(jvmId, filename, filter);
}
String key = recordingHelper.archivedRecordingKey(jvmId, filename);
logger.tracev("reportFor {0}", key);
return archivedCache.getAsync(
key,
k -> {
logger.tracev("reportFor {0} cache miss", k);
return delegate.reportFor(jvmId, filename);
return delegate.reportFor(jvmId, filename, filter);
});
}

@Override
public Uni<Map<String, AnalysisResult>> reportFor(ActiveRecording recording) {
return reportFor(recording, r -> true);
return reportFor(recording, null);
}

@Override
public Uni<Map<String, AnalysisResult>> reportFor(String jvmId, String filename) {
return reportFor(jvmId, filename, r -> true);
return reportFor(jvmId, filename, null);
}

@Override
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/io/cryostat/reports/ReportSidecarService.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ public interface ReportSidecarService {
@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
Uni<Map<String, AnalysisResult>> generate(
@RestForm("file") @PartType(MediaType.APPLICATION_OCTET_STREAM) InputStream file);
@RestForm("file") @PartType(MediaType.APPLICATION_OCTET_STREAM) InputStream file,
@RestForm("filter") @PartType(MediaType.TEXT_PLAIN) String filter);

@Path("/remote_report")
@POST
Expand Down
Loading
Loading