Skip to content
Draft
Show file tree
Hide file tree
Changes from 2 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.comet.opik.api.metrics;

import com.comet.opik.api.TimeInterval;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.databind.annotation.JsonNaming;
import jakarta.validation.Valid;
import jakarta.validation.constraints.AssertTrue;
import jakarta.validation.constraints.NotNull;
import lombok.Builder;

import java.time.Instant;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;

/**
* Request for workspace-level span metrics aggregated across projects. When {@code projectIds} is empty, all projects
* in the workspace are included; otherwise only the given projects. {@code intervalEnd} is optional and defaults to
* "now" server-side, mirroring the per-project metrics endpoint.
*/
@Builder(toBuilder = true)
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
public record WorkspaceSpanMetricRequest(
Set<@NotNull UUID> projectIds,
MetricType metricType,
TimeInterval interval,
@Valid BreakdownConfig breakdown,
@NotNull Instant intervalStart,
Instant intervalEnd) {

@AssertTrue(message = "intervalStart must be before intervalEnd") public boolean isStartBeforeEnd() {
return intervalEnd == null || intervalStart.isBefore(intervalEnd);
}

public boolean hasBreakdown() {
return Optional.ofNullable(breakdown)
.map(BreakdownQueryBuilder::isEnabled)
.orElse(false);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import com.comet.opik.api.metrics.WorkspaceMetricResponse;
import com.comet.opik.api.metrics.WorkspaceMetricsSummaryRequest;
import com.comet.opik.api.metrics.WorkspaceMetricsSummaryResponse;
import com.comet.opik.api.metrics.WorkspaceSpanMetricRequest;
import com.comet.opik.domain.WorkspaceConfigurationService;
import com.comet.opik.domain.WorkspaceMetricsService;
import com.comet.opik.domain.workspaces.WorkspaceVersionService;
Expand Down Expand Up @@ -150,6 +151,29 @@ public Response getCost(
return Response.ok().entity(response).build();
}

@POST
@Path("/metrics/spans")
@Operation(operationId = "getWorkspaceSpanMetric", summary = "Get workspace span metric", description = "Gets a span metric time series aggregated across the workspace. When project_ids is empty, all projects in the workspace are included; otherwise only the given projects.", responses = {
@ApiResponse(responseCode = "200", description = "Workspace span metric", content = @Content(schema = @Schema(implementation = WorkspaceMetricResponse.class))),
@ApiResponse(responseCode = "400", description = "Bad Request", content = @Content(schema = @Schema(implementation = ErrorMessage.class)))
})
@RequiredPermissions(WorkspaceUserPermission.PROJECT_DATA_VIEW)
public Response getWorkspaceSpanMetric(
@RequestBody(content = @Content(schema = @Schema(implementation = WorkspaceSpanMetricRequest.class))) @NotNull @Valid WorkspaceSpanMetricRequest request) {

String workspaceId = requestContext.get().getWorkspaceId();

log.info("Retrieve workspace span metric '{}' for projectIds '{}', on workspace_id '{}'", request.metricType(),
request.projectIds(), workspaceId);
WorkspaceMetricResponse response = workspaceMetricsService.getWorkspaceSpanMetric(request)
.contextWrite(ctx -> setRequestContext(ctx, requestContext))
.block();
log.info("Retrieved workspace span metric '{}' for projectIds '{}', on workspace_id '{}'", request.metricType(),
request.projectIds(), workspaceId);

return Response.ok().entity(response).build();
}

@GET
@Path("/versions")
@Operation(operationId = "getWorkspaceVersion", summary = "Get workspace version", description = """
Expand Down
Loading
Loading