From ac91bf0258f5d150adf2a2cff88cf65c85895cb9 Mon Sep 17 00:00:00 2001 From: Thiago dos Santos Hora Date: Mon, 16 Sep 2024 12:27:20 +0200 Subject: [PATCH] [NA] Add info logs (#242) --- .../resources/v1/priv/DatasetsResource.java | 118 ++++++++++++++---- .../v1/priv/FeedbackDefinitionResource.java | 44 +++++-- .../resources/v1/priv/ProjectsResource.java | 39 +++++- .../api/resources/v1/priv/SpansResource.java | 64 ++++++---- .../api/resources/v1/priv/TraceResource.java | 65 +++++++++- .../com/comet/opik/domain/DatasetDAO.java | 3 - .../comet/opik/domain/DatasetItemService.java | 8 +- .../com/comet/opik/domain/DatasetService.java | 19 ++- .../opik/domain/ExperimentItemService.java | 19 +-- .../comet/opik/domain/ExperimentService.java | 9 +- .../opik/domain/FeedbackDefinitionDAO.java | 3 - .../domain/FeedbackDefinitionService.java | 21 ++-- .../opik/domain/FeedbackScoreService.java | 9 +- .../com/comet/opik/domain/ProjectDAO.java | 3 - .../com/comet/opik/domain/ProjectService.java | 43 ++++--- .../com/comet/opik/domain/SpanService.java | 5 +- .../com/comet/opik/domain/TraceService.java | 4 + 17 files changed, 347 insertions(+), 129 deletions(-) diff --git a/apps/opik-backend/src/main/java/com/comet/opik/api/resources/v1/priv/DatasetsResource.java b/apps/opik-backend/src/main/java/com/comet/opik/api/resources/v1/priv/DatasetsResource.java index e90b80455f..cb54d09b53 100644 --- a/apps/opik-backend/src/main/java/com/comet/opik/api/resources/v1/priv/DatasetsResource.java +++ b/apps/opik-backend/src/main/java/com/comet/opik/api/resources/v1/priv/DatasetsResource.java @@ -98,7 +98,13 @@ public class DatasetsResource { @JsonView(Dataset.View.Public.class) public Response getDatasetById(@PathParam("id") UUID id) { - return Response.ok().entity(service.findById(id)).build(); + String workspaceId = requestContext.get().getWorkspaceId(); + + log.info("Finding dataset by id '{}' on workspaceId '{}'", id, workspaceId); + Dataset dataset = service.findById(id); + log.info("Found dataset by id '{}' on workspaceId '{}'", id, workspaceId); + + return Response.ok().entity(dataset).build(); } @GET @@ -115,7 +121,13 @@ public Response findDatasets( .name(name) .build(); - return Response.ok(service.find(page, size, criteria)).build(); + String workspaceId = requestContext.get().getWorkspaceId(); + + log.info("Finding datasets by '{}' on workspaceId '{}'", criteria, workspaceId); + DatasetPage datasetPage = service.find(page, size, criteria); + log.info("Found datasets by '{}', count '{}' on workspaceId '{}'", criteria, datasetPage.size(), workspaceId); + + return Response.ok(datasetPage).build(); } @POST @@ -128,7 +140,14 @@ public Response createDataset( @RequestBody(content = @Content(schema = @Schema(implementation = Dataset.class))) @JsonView(Dataset.View.Write.class) @NotNull @Valid Dataset dataset, @Context UriInfo uriInfo) { - URI uri = uriInfo.getAbsolutePathBuilder().path("/%s".formatted(service.save(dataset).id().toString())).build(); + String workspaceId = requestContext.get().getWorkspaceId(); + + log.info("Creating dataset with name '{}', on workspace_id '{}'", dataset.name(), workspaceId); + Dataset savedDataset = service.save(dataset); + log.info("Created dataset with name '{}', id '{}', on workspace_id '{}'", savedDataset.name(), + savedDataset.id(), workspaceId); + + URI uri = uriInfo.getAbsolutePathBuilder().path("/%s".formatted(savedDataset.id().toString())).build(); return Response.created(uri).build(); } @@ -140,7 +159,11 @@ public Response createDataset( public Response updateDataset(@PathParam("id") UUID id, @RequestBody(content = @Content(schema = @Schema(implementation = DatasetUpdate.class))) @NotNull @Valid DatasetUpdate datasetUpdate) { + String workspaceId = requestContext.get().getWorkspaceId(); + log.info("Updating dataset by id '{}' on workspace_id '{}'", id, workspaceId); service.update(id, datasetUpdate); + log.info("Updated dataset by id '{}' on workspace_id '{}'", id, workspaceId); + return Response.noContent().build(); } @@ -151,7 +174,10 @@ public Response updateDataset(@PathParam("id") UUID id, }) public Response deleteDataset(@PathParam("id") UUID id) { + String workspaceId = requestContext.get().getWorkspaceId(); + log.info("Deleting dataset by id '{}' on workspace_id '{}'", id, workspaceId); service.delete(id); + log.info("Deleted dataset by id '{}' on workspace_id '{}'", id, workspaceId); return Response.noContent().build(); } @@ -163,7 +189,12 @@ public Response deleteDataset(@PathParam("id") UUID id) { public Response deleteDatasetByName( @RequestBody(content = @Content(schema = @Schema(implementation = DatasetIdentifier.class))) @NotNull @Valid DatasetIdentifier identifier) { + String workspaceId = requestContext.get().getWorkspaceId(); + + log.info("Deleting dataset by name '{}' on workspace_id '{}'", identifier.datasetName(), workspaceId); service.delete(identifier); + log.info("Deleted dataset by name '{}' on workspace_id '{}'", identifier.datasetName(), workspaceId); + return Response.noContent().build(); } @@ -179,7 +210,11 @@ public Response getDatasetByIdentifier( String workspaceId = requestContext.get().getWorkspaceId(); String name = identifier.datasetName(); - return Response.ok(service.findByName(workspaceId, name)).build(); + log.info("Finding dataset by name '{}' on workspace_id '{}'", name, workspaceId); + Dataset dataset = service.findByName(workspaceId, name); + log.info("Found dataset by name '{}', id '{}' on workspace_id '{}'", name, dataset.id(), workspaceId); + + return Response.ok(dataset).build(); } // Dataset Item Resources @@ -192,9 +227,15 @@ public Response getDatasetByIdentifier( @JsonView(DatasetItem.View.Public.class) public Response getDatasetItemById(@PathParam("itemId") @NotNull UUID itemId) { - return Response.ok(itemService.get(itemId) + String workspaceId = requestContext.get().getWorkspaceId(); + + log.info("Finding dataset item by id '{}' on workspace_id '{}'", itemId, workspaceId); + DatasetItem datasetItem = itemService.get(itemId) .contextWrite(ctx -> setRequestContext(ctx, requestContext)) - .block()).build(); + .block(); + log.info("Found dataset item by id '{}' on workspace_id '{}'", itemId, workspaceId); + + return Response.ok(datasetItem).build(); } @GET @@ -208,10 +249,16 @@ public Response getDatasetItems( @QueryParam("page") @Min(1) @DefaultValue("1") int page, @QueryParam("size") @Min(1) @DefaultValue("10") int size) { - return Response.ok(itemService.getItems(id, page, size) + String workspaceId = requestContext.get().getWorkspaceId(); + log.info("Finding dataset items by id '{}', page '{}', size '{} on workspace_id '{}''", id, page, size, + workspaceId); + DatasetItem.DatasetItemPage datasetItemPage = itemService.getItems(id, page, size) .contextWrite(ctx -> setRequestContext(ctx, requestContext)) - .block()) - .build(); + .block(); + log.info("Found dataset items by id '{}', count '{}', page '{}', size '{} on workspace_id '{}''", id, + datasetItemPage.content().size(), page, size, workspaceId); + + return Response.ok(datasetItemPage).build(); } @POST @@ -226,12 +273,14 @@ public Response getDatasetItems( public ChunkedOutput streamDatasetItems( @RequestBody(content = @Content(schema = @Schema(implementation = DatasetItemStreamRequest.class))) @NotNull @Valid DatasetItemStreamRequest request) { + String workspaceId = requestContext.get().getWorkspaceId(); + log.info("Streaming dataset items by '{}' on workspaceId '{}'", request, workspaceId); return getOutputStream(request, request.steamLimit()); } private ChunkedOutput getOutputStream(DatasetItemStreamRequest request, int limit) { - final ChunkedOutput outputStream = new ChunkedOutput<>(JsonNode.class, "\r\n"); + ChunkedOutput outputStream = new ChunkedOutput<>(JsonNode.class, "\r\n"); String workspaceId = requestContext.get().getWorkspaceId(); String userName = requestContext.get().getUserName(); @@ -239,16 +288,21 @@ private ChunkedOutput getOutputStream(DatasetItemStreamRequest request Schedulers .boundedElastic() - .schedule(() -> Mono.fromCallable(() -> service.findByName(workspaceId, request.datasetName())) - .subscribeOn(Schedulers.boundedElastic()) - .flatMapMany(dataset -> itemService.getItems(dataset.id(), limit, request.lastRetrievedId())) - .doOnNext(item -> sendDatasetItems(item, outputStream)) - .onErrorResume(ex -> errorHandling(ex, outputStream)) - .doFinally(signalType -> closeOutput(outputStream)) - .contextWrite(ctx -> ctx.put(RequestContext.USER_NAME, userName) - .put(RequestContext.WORKSPACE_NAME, workspaceName) - .put(RequestContext.WORKSPACE_ID, workspaceId)) - .subscribe()); + .schedule(() -> { + Mono.fromCallable(() -> service.findByName(workspaceId, request.datasetName())) + .subscribeOn(Schedulers.boundedElastic()) + .flatMapMany( + dataset -> itemService.getItems(dataset.id(), limit, request.lastRetrievedId())) + .doOnNext(item -> sendDatasetItems(item, outputStream)) + .onErrorResume(ex -> errorHandling(ex, outputStream)) + .doFinally(signalType -> closeOutput(outputStream)) + .contextWrite(ctx -> ctx.put(RequestContext.USER_NAME, userName) + .put(RequestContext.WORKSPACE_NAME, workspaceName) + .put(RequestContext.WORKSPACE_ID, workspaceId)) + .subscribe(); + + log.info("Streamed dataset items by '{}' on workspaceId '{}'", request, workspaceId); + }); return outputStream; } @@ -304,10 +358,16 @@ public Response createDatasetItems( return item; }).toList(); + String workspaceId = requestContext.get().getWorkspaceId(); + + log.info("Creating dataset items batch by datasetId '{}', datasetName '{}', size '{}' on workspaceId '{}'", + batch.datasetId(), batch.datasetId(), batch.items().size(), workspaceId); itemService.save(new DatasetItemBatch(batch.datasetName(), batch.datasetId(), items)) .contextWrite(ctx -> setRequestContext(ctx, requestContext)) .retryWhen(AsyncUtils.handleConnectionError()) .block(); + log.info("Created dataset items batch by datasetId '{}', datasetName '{}', size '{}' on workspaceId '{}'", + batch.datasetId(), batch.datasetId(), batch.items().size(), workspaceId); return Response.noContent().build(); } @@ -320,9 +380,14 @@ public Response createDatasetItems( public Response deleteDatasetItems( @RequestBody(content = @Content(schema = @Schema(implementation = DatasetItemsDelete.class))) @NotNull @Valid DatasetItemsDelete request) { + String workspaceId = requestContext.get().getWorkspaceId(); + + log.info("Deleting dataset items by size'{}' on workspaceId '{}'", request, workspaceId); itemService.delete(request.itemIds()) .contextWrite(ctx -> setRequestContext(ctx, requestContext)) .block(); + log.info("Deleted dataset items by size'{}' on workspaceId '{}'", request, workspaceId); + return Response.noContent().build(); } @@ -347,13 +412,18 @@ public Response findDatasetItemsWithExperimentItems( .entityType(FeedbackScoreDAO.EntityType.TRACE) .build(); - log.info("Finding dataset items with experiment items by '{}', page '{}', size '{}'", - datasetItemSearchCriteria, page, size); + String workspaceId = requestContext.get().getWorkspaceId(); + + log.info("Finding dataset items with experiment items by '{}', page '{}', size '{}' on workspaceId '{}'", + datasetItemSearchCriteria, page, size, workspaceId); + var datasetItemPage = itemService.getItems(page, size, datasetItemSearchCriteria) .contextWrite(ctx -> setRequestContext(ctx, requestContext)) .block(); - log.info("Found dataset items with experiment items by '{}', count '{}', page '{}', size '{}'", - datasetItemSearchCriteria, datasetItemPage.content().size(), page, size); + + log.info( + "Found dataset items with experiment items by '{}', count '{}', page '{}', size '{}' on workspaceId '{}'", + datasetItemSearchCriteria, datasetItemPage.content().size(), page, size, workspaceId); return Response.ok(datasetItemPage).build(); } diff --git a/apps/opik-backend/src/main/java/com/comet/opik/api/resources/v1/priv/FeedbackDefinitionResource.java b/apps/opik-backend/src/main/java/com/comet/opik/api/resources/v1/priv/FeedbackDefinitionResource.java index 1a71beedc4..c3a2d9ccc0 100644 --- a/apps/opik-backend/src/main/java/com/comet/opik/api/resources/v1/priv/FeedbackDefinitionResource.java +++ b/apps/opik-backend/src/main/java/com/comet/opik/api/resources/v1/priv/FeedbackDefinitionResource.java @@ -3,7 +3,9 @@ import com.codahale.metrics.annotation.Timed; import com.comet.opik.api.FeedbackDefinition; import com.comet.opik.api.FeedbackDefinitionCriteria; +import com.comet.opik.api.Page; import com.comet.opik.domain.FeedbackDefinitionService; +import com.comet.opik.infrastructure.auth.RequestContext; import com.fasterxml.jackson.annotation.JsonView; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.headers.Header; @@ -13,6 +15,7 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.inject.Inject; +import jakarta.inject.Provider; import jakarta.validation.Valid; import jakarta.validation.constraints.Min; import jakarta.validation.constraints.NotNull; @@ -48,6 +51,7 @@ public class FeedbackDefinitionResource { private final @NonNull FeedbackDefinitionService service; + private final @NonNull Provider requestContext; @GET @Operation(operationId = "findFeedbackDefinitions", summary = "Find Feedback definitions", description = "Find Feedback definitions", responses = { @@ -65,8 +69,13 @@ public Response find( .type(type) .build(); + String workspaceId = requestContext.get().getWorkspaceId(); + log.info("Find feedback definitions by '{}' on workspaceId '{}'", criteria, workspaceId); + Page> definitionPage = service.find(page, size, criteria); + log.info("Found feedback definitions by '{}' on workspaceId '{}'", criteria, workspaceId); + return Response.ok() - .entity(service.find(page, size, criteria)) + .entity(definitionPage) .build(); } @@ -77,7 +86,13 @@ public Response find( }) @JsonView({FeedbackDefinition.View.Public.class}) public Response getById(@PathParam("id") @NotNull UUID id) { - return Response.ok().entity(service.get(id)).build(); + + String workspaceId = requestContext.get().getWorkspaceId(); + log.info("Get feedback definition by id '{}' on workspaceId '{}'", id, workspaceId); + FeedbackDefinition feedbackDefinition = service.get(id); + log.info("Got feedback definition by id '{}' on workspaceId '{}'", id, workspaceId); + + return Response.ok().entity(feedbackDefinition).build(); } @POST @@ -90,8 +105,14 @@ public Response create( FeedbackDefinition.View.Create.class}) @NotNull @Valid FeedbackDefinition feedbackDefinition, @Context UriInfo uriInfo) { - final var createdFeedbackDefinitions = service.create(feedbackDefinition); - final var uri = uriInfo.getAbsolutePathBuilder().path("/%s".formatted(createdFeedbackDefinitions.getId())) + String workspaceId = requestContext.get().getWorkspaceId(); + log.info("Creating feedback definition with id '{}', name '{}' on workspaceId '{}'", feedbackDefinition.getId(), + feedbackDefinition.getName(), workspaceId); + FeedbackDefinition createdFeedbackDefinition = service.create(feedbackDefinition); + log.info("Created feedback definition with id '{}', name '{}' on workspaceId '{}'", + createdFeedbackDefinition.getId(), createdFeedbackDefinition.getName(), workspaceId); + + var uri = uriInfo.getAbsolutePathBuilder().path("/%s".formatted(createdFeedbackDefinition.getId())) .build(); return Response.created(uri).build(); @@ -106,7 +127,13 @@ public Response update(final @PathParam("id") UUID id, @RequestBody(content = @Content(schema = @Schema(implementation = FeedbackDefinition.class))) @JsonView({ FeedbackDefinition.View.Update.class}) @NotNull @Valid FeedbackDefinition feedbackDefinition) { + String workspaceId = requestContext.get().getWorkspaceId(); + log.info("Updating feedback definition with id '{}' on workspaceId '{}'", feedbackDefinition.getId(), + workspaceId); service.update(id, feedbackDefinition); + log.info("Updated feedback definition with id '{}' on workspaceId '{}'", feedbackDefinition.getId(), + workspaceId); + return Response.noContent().build(); } @@ -117,13 +144,12 @@ public Response update(final @PathParam("id") UUID id, }) public Response deleteById(@PathParam("id") UUID id) { - var workspace = service.getWorkspaceId(id); - - if (workspace == null) { - return Response.noContent().build(); - } + String workspaceId = requestContext.get().getWorkspaceId(); + log.info("Deleting feedback definition by id '{}' on workspaceId '{}'", id, workspaceId); service.delete(id); + log.info("Deleted feedback definition by id '{}' on workspaceId '{}'", id, workspaceId); + return Response.noContent().build(); } diff --git a/apps/opik-backend/src/main/java/com/comet/opik/api/resources/v1/priv/ProjectsResource.java b/apps/opik-backend/src/main/java/com/comet/opik/api/resources/v1/priv/ProjectsResource.java index 79376e4a51..f6e05d4b9c 100644 --- a/apps/opik-backend/src/main/java/com/comet/opik/api/resources/v1/priv/ProjectsResource.java +++ b/apps/opik-backend/src/main/java/com/comet/opik/api/resources/v1/priv/ProjectsResource.java @@ -1,11 +1,13 @@ package com.comet.opik.api.resources.v1.priv; import com.codahale.metrics.annotation.Timed; +import com.comet.opik.api.Page; import com.comet.opik.api.Project; import com.comet.opik.api.ProjectCriteria; import com.comet.opik.api.ProjectUpdate; import com.comet.opik.api.error.ErrorMessage; import com.comet.opik.domain.ProjectService; +import com.comet.opik.infrastructure.auth.RequestContext; import com.fasterxml.jackson.annotation.JsonView; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.headers.Header; @@ -15,6 +17,7 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.inject.Inject; +import jakarta.inject.Provider; import jakarta.validation.Valid; import jakarta.validation.constraints.Min; import jakarta.ws.rs.Consumes; @@ -47,6 +50,7 @@ public class ProjectsResource { private final @NonNull ProjectService projectService; + private final @NonNull Provider requestContext; @GET @Operation(operationId = "findProjects", summary = "Find projects", description = "Find projects", responses = { @@ -62,7 +66,13 @@ public Response find( .projectName(name) .build(); - return Response.ok().entity(projectService.find(page, size, criteria)).build(); + String workspaceId = requestContext.get().getWorkspaceId(); + + log.info("Find projects by '{}' on workspaceId '{}'", criteria, workspaceId); + Page projectPage = projectService.find(page, size, criteria); + log.info("Found projects by '{}', count '{}' on workspaceId '{}'", criteria, projectPage.size(), workspaceId); + + return Response.ok().entity(projectPage).build(); } @GET @@ -71,7 +81,16 @@ public Response find( @ApiResponse(responseCode = "200", description = "Project resource", content = @Content(schema = @Schema(implementation = Project.class)))}) @JsonView({Project.View.Public.class}) public Response getById(@PathParam("id") UUID id) { - return Response.ok().entity(projectService.get(id)).build(); + + String workspaceId = requestContext.get().getWorkspaceId(); + + log.info("Getting project by id '{}' on workspace_id '{}'", id, workspaceId); + + Project project = projectService.get(id); + + log.info("Got project by id '{}' on workspace_id '{}'", id, workspaceId); + + return Response.ok().entity(project).build(); } @POST @@ -85,8 +104,15 @@ public Response create( @RequestBody(content = @Content(schema = @Schema(implementation = Project.class))) @JsonView(Project.View.Write.class) @Valid Project project, @Context UriInfo uriInfo) { + String workspaceId = requestContext.get().getWorkspaceId(); + + log.info("Creating project with name '{}', on workspace_id '{}'", project.name(), workspaceId); + var projectId = projectService.create(project).id(); + log.info("Created project with name '{}', id '{}', on workspace_id '{}'", project.name(), projectId, + workspaceId); + var uri = uriInfo.getAbsolutePathBuilder().path("/%s".formatted(projectId)).build(); return Response.created(uri).build(); @@ -102,7 +128,12 @@ public Response create( public Response update(@PathParam("id") UUID id, @RequestBody(content = @Content(schema = @Schema(implementation = ProjectUpdate.class))) @Valid ProjectUpdate project) { + String workspaceId = requestContext.get().getWorkspaceId(); + + log.info("Updating project with id '{}' on workspaceId '{}'", id, workspaceId); projectService.update(id, project); + log.info("Updated project with id '{}' on workspaceId '{}'", id, workspaceId); + return Response.noContent().build(); } @@ -114,7 +145,11 @@ public Response update(@PathParam("id") UUID id, }) public Response deleteById(@PathParam("id") UUID id) { + String workspaceId = requestContext.get().getWorkspaceId(); + + log.info("Deleting project by id '{}' on workspaceId '{}'", id, workspaceId); projectService.delete(id); + log.info("Deleted project by id '{}' on workspaceId '{}'", id, workspaceId); return Response.noContent().build(); } diff --git a/apps/opik-backend/src/main/java/com/comet/opik/api/resources/v1/priv/SpansResource.java b/apps/opik-backend/src/main/java/com/comet/opik/api/resources/v1/priv/SpansResource.java index e337363f76..968bd9d870 100644 --- a/apps/opik-backend/src/main/java/com/comet/opik/api/resources/v1/priv/SpansResource.java +++ b/apps/opik-backend/src/main/java/com/comet/opik/api/resources/v1/priv/SpansResource.java @@ -51,6 +51,8 @@ import java.util.UUID; import java.util.stream.Collectors; +import static com.comet.opik.api.Span.SpanPage; +import static com.comet.opik.api.Span.View; import static com.comet.opik.utils.AsyncUtils.setRequestContext; import static com.comet.opik.utils.ValidationUtils.validateProjectNameAndProjectId; @@ -70,8 +72,8 @@ public class SpansResource { @GET @Operation(operationId = "getSpansByProject", summary = "Get spans by project_name or project_id and optionally by trace_id and/or type", description = "Get spans by project_name or project_id and optionally by trace_id and/or type", responses = { - @ApiResponse(responseCode = "200", description = "Spans resource", content = @Content(schema = @Schema(implementation = Span.SpanPage.class)))}) - @JsonView(Span.View.Public.class) + @ApiResponse(responseCode = "200", description = "Spans resource", content = @Content(schema = @Schema(implementation = SpanPage.class)))}) + @JsonView(View.Public.class) public Response getByProjectId( @QueryParam("page") @Min(1) @DefaultValue("1") int page, @QueryParam("size") @Min(1) @DefaultValue("10") int size, @@ -91,11 +93,13 @@ public Response getByProjectId( .filters(spanFilters) .build(); - log.info("Get spans by '{}'", spanSearchCriteria); - var spans = spanService.find(page, size, spanSearchCriteria) + String workspaceId = requestContext.get().getWorkspaceId(); + + log.info("Get spans by '{}' on workspaceId '{}'", spanSearchCriteria, workspaceId); + SpanPage spans = spanService.find(page, size, spanSearchCriteria) .contextWrite(ctx -> setRequestContext(ctx, requestContext)) .block(); - log.info("Found spans by '{}', count '{}'", spanSearchCriteria, spans.size()); + log.info("Found spans by '{}', count '{}' on workspaceId '{}'", spanSearchCriteria, spans.size(), workspaceId); return Response.ok().entity(spans).build(); } @@ -104,15 +108,18 @@ public Response getByProjectId( @Operation(operationId = "getSpanById", summary = "Get span by id", description = "Get span by id", responses = { @ApiResponse(responseCode = "200", description = "Span resource", content = @Content(schema = @Schema(implementation = Span.class))), @ApiResponse(responseCode = "404", description = "Not found", content = @Content(schema = @Schema(implementation = Span.class)))}) - @JsonView(Span.View.Public.class) + @JsonView(View.Public.class) public Response getById(@PathParam("id") @NotNull UUID id) { - log.info("Getting span by id '{}'", id); + String workspaceId = requestContext.get().getWorkspaceId(); + + log.info("Getting span by id '{}' on workspace_id '{}'", id, workspaceId); var span = spanService.getById(id) .contextWrite(ctx -> setRequestContext(ctx, requestContext)) .block(); - log.info("Got span by id '{}', traceId '{}', parentSpanId '{}'", span.id(), span.traceId(), - span.parentSpanId()); + log.info("Got span by id '{}', traceId '{}', parentSpanId '{}' on workspace_id '{}'", span.id(), span.traceId(), + span.parentSpanId(), workspaceId); + return Response.ok().entity(span).build(); } @@ -121,17 +128,20 @@ public Response getById(@PathParam("id") @NotNull UUID id) { @ApiResponse(responseCode = "201", description = "Created", headers = { @Header(name = "Location", required = true, example = "${basePath}/v1/private/spans/{spanId}", schema = @Schema(implementation = String.class))})}) public Response create( - @RequestBody(content = @Content(schema = @Schema(implementation = Span.class))) @JsonView(Span.View.Write.class) @NotNull @Valid Span span, + @RequestBody(content = @Content(schema = @Schema(implementation = Span.class))) @JsonView(View.Write.class) @NotNull @Valid Span span, @Context UriInfo uriInfo) { - log.info("Creating span with id '{}', projectId '{}', traceId '{}', parentSpanId '{}'", - span.id(), span.projectId(), span.traceId(), span.parentSpanId()); + String workspaceId = requestContext.get().getWorkspaceId(); + + log.info("Creating span with id '{}', projectName '{}', traceId '{}', parentSpanId '{}' on workspace_id '{}'", + span.id(), span.projectName(), span.traceId(), span.parentSpanId(), workspaceId); + var id = spanService.create(span) .contextWrite(ctx -> setRequestContext(ctx, requestContext)) .block(); var uri = uriInfo.getAbsolutePathBuilder().path("/%s".formatted(id)).build(); - log.info("Created span with id '{}', projectId '{}', traceId '{}', parentSpanId '{}', workspaceId '{}'", - id, span.projectId(), span.traceId(), span.parentSpanId(), requestContext.get().getWorkspaceId()); + log.info("Created span with id '{}', projectName '{}', traceId '{}', parentSpanId '{}' on workspaceId '{}'", + id, span.projectName(), span.traceId(), span.parentSpanId(), workspaceId); return Response.created(uri).build(); } @@ -167,11 +177,13 @@ public Response createSpans( public Response update(@PathParam("id") UUID id, @RequestBody(content = @Content(schema = @Schema(implementation = SpanUpdate.class))) @NotNull @Valid SpanUpdate spanUpdate) { - log.info("Updating span with id '{}'", id); + String workspaceId = requestContext.get().getWorkspaceId(); + + log.info("Updating span with id '{}' on workspaceId '{}'", id, workspaceId); spanService.update(id, spanUpdate) .contextWrite(ctx -> setRequestContext(ctx, requestContext)) .block(); - log.info("Updated span with id '{}'", id); + log.info("Updated span with id '{}' on workspaceId '{}'", id, workspaceId); return Response.noContent().build(); } @@ -182,7 +194,7 @@ public Response update(@PathParam("id") UUID id, @ApiResponse(responseCode = "204", description = "No Content")}) public Response deleteById(@PathParam("id") @NotNull String id) { - log.info("Deleting span with id '{}'", id); + log.info("Deleting span with id '{}' on workspaceId '{}'", id, requestContext.get().getWorkspaceId()); return Response.status(501).build(); } @@ -193,11 +205,13 @@ public Response deleteById(@PathParam("id") @NotNull String id) { public Response addSpanFeedbackScore(@PathParam("id") UUID id, @RequestBody(content = @Content(schema = @Schema(implementation = FeedbackScore.class))) @NotNull @Valid FeedbackScore score) { - log.info("Add span feedback score '{}' for id '{}'", score.name(), id); + String workspaceId = requestContext.get().getWorkspaceId(); + + log.info("Add span feedback score '{}' for id '{}' on workspaceId '{}'", score.name(), id, workspaceId); feedbackScoreService.scoreSpan(id, score) .contextWrite(ctx -> setRequestContext(ctx, requestContext)) .block(); - log.info("Added span feedback score '{}' for id '{}'", score.name(), id); + log.info("Added span feedback score '{}' for id '{}' on workspaceId '{}'", score.name(), id, workspaceId); return Response.noContent().build(); } @@ -209,11 +223,13 @@ public Response addSpanFeedbackScore(@PathParam("id") UUID id, public Response deleteSpanFeedbackScore(@PathParam("id") UUID id, @RequestBody(content = @Content(schema = @Schema(implementation = DeleteFeedbackScore.class))) @NotNull @Valid DeleteFeedbackScore score) { - log.info("Delete span feedback score '{}' for id '{}'", score.name(), id); + String workspaceId = requestContext.get().getWorkspaceId(); + + log.info("Delete span feedback score '{}' for id '{}' on workspaceId '{}'", score.name(), id, workspaceId); feedbackScoreService.deleteSpanScore(id, score.name()) .contextWrite(ctx -> setRequestContext(ctx, requestContext)) .block(); - log.info("Deleted span feedback score '{}' for id '{}'", score.name(), id); + log.info("Deleted span feedback score '{}' for id '{}' on workspaceId '{}'", score.name(), id, workspaceId); return Response.noContent().build(); } @@ -224,12 +240,14 @@ public Response deleteSpanFeedbackScore(@PathParam("id") UUID id, public Response scoreBatchOfSpans( @RequestBody(content = @Content(schema = @Schema(implementation = FeedbackScoreBatch.class))) @NotNull @Valid FeedbackScoreBatch batch) { - log.info("Score batch of spans"); + String workspaceId = requestContext.get().getWorkspaceId(); + + log.info("Feedback scores batch for spans, size {} on workspaceId '{}'", batch.scores().size(), workspaceId); feedbackScoreService.scoreBatchOfSpans(batch.scores()) .contextWrite(ctx -> setRequestContext(ctx, requestContext)) .retryWhen(AsyncUtils.handleConnectionError()) .block(); - log.info("Scored batch of spans"); + log.info("Scored batch for spans, size {} on workspaceId '{}'", batch.scores().size(), workspaceId); return Response.noContent().build(); } diff --git a/apps/opik-backend/src/main/java/com/comet/opik/api/resources/v1/priv/TraceResource.java b/apps/opik-backend/src/main/java/com/comet/opik/api/resources/v1/priv/TraceResource.java index bd1c77aca1..31bf42715c 100644 --- a/apps/opik-backend/src/main/java/com/comet/opik/api/resources/v1/priv/TraceResource.java +++ b/apps/opik-backend/src/main/java/com/comet/opik/api/resources/v1/priv/TraceResource.java @@ -5,6 +5,7 @@ import com.comet.opik.api.FeedbackScore; import com.comet.opik.api.FeedbackScoreBatch; import com.comet.opik.api.Trace; +import com.comet.opik.api.Trace.TracePage; import com.comet.opik.api.TraceBatch; import com.comet.opik.api.TraceSearchCriteria; import com.comet.opik.api.TraceUpdate; @@ -68,7 +69,7 @@ public class TraceResource { @GET @Operation(operationId = "getTracesByProject", summary = "Get traces by project_name or project_id", description = "Get traces by project_name or project_id", responses = { - @ApiResponse(responseCode = "200", description = "Trace resource", content = @Content(schema = @Schema(implementation = Trace.TracePage.class)))}) + @ApiResponse(responseCode = "200", description = "Trace resource", content = @Content(schema = @Schema(implementation = TracePage.class)))}) @JsonView(Trace.View.Public.class) public Response getByProjectId( @QueryParam("page") @Min(1) @DefaultValue("1") int page, @@ -84,10 +85,18 @@ public Response getByProjectId( .projectId(projectId) .filters(traceFilters) .build(); - return service.find(page, size, searchCriteria) - .map(tracesPage -> Response.ok(tracesPage).build()) + + String workspaceId = requestContext.get().getWorkspaceId(); + + log.info("Get traces by '{}' on workspaceId '{}'", searchCriteria, workspaceId); + + TracePage tracePage = service.find(page, size, searchCriteria) .contextWrite(ctx -> setRequestContext(ctx, requestContext)) .block(); + + log.info("Found traces by '{}', count '{}' on workspaceId '{}'", searchCriteria, tracePage.size(), workspaceId); + + return Response.ok(tracePage).build(); } @GET @@ -97,10 +106,18 @@ public Response getByProjectId( @JsonView(Trace.View.Public.class) public Response getById(@PathParam("id") UUID id) { - return service.get(id) - .map(trace -> Response.ok(trace).build()) + String workspaceId = requestContext.get().getWorkspaceId(); + + log.info("Getting trace by id '{}' on workspace_id '{}'", id, workspaceId); + + Trace trace = service.get(id) .contextWrite(ctx -> setRequestContext(ctx, requestContext)) .block(); + + log.info("Got trace by id '{}', projectId '{}' on workspace_id '{}'", trace.id(), trace.projectId(), + workspaceId); + + return Response.ok(trace).build(); } @POST @@ -111,10 +128,20 @@ public Response create( @RequestBody(content = @Content(schema = @Schema(implementation = Trace.class))) @JsonView(Trace.View.Write.class) @NotNull @Valid Trace trace, @Context UriInfo uriInfo) { + String workspaceId = requestContext.get().getWorkspaceId(); + + log.info("Creating trace with id '{}', projectName '{}' on workspace_id '{}'", + trace.id(), trace.projectName(), workspaceId); + var id = service.create(trace) .contextWrite(ctx -> setRequestContext(ctx, requestContext)) .block(); + + log.info("Created trace with id '{}', projectName '{}' on workspace_id '{}'", + id, trace.projectName(), workspaceId); + var uri = uriInfo.getAbsolutePathBuilder().path("/%s".formatted(id)).build(); + return Response.created(uri).build(); } @@ -149,10 +176,16 @@ public Response createSpans( public Response update(@PathParam("id") UUID id, @RequestBody(content = @Content(schema = @Schema(implementation = TraceUpdate.class))) @Valid @NonNull TraceUpdate trace) { + String workspaceId = requestContext.get().getWorkspaceId(); + + log.info("Updating span with id '{}' on workspaceId '{}'", id, workspaceId); + service.update(trace, id) .contextWrite(ctx -> setRequestContext(ctx, requestContext)) .block(); + log.info("Updated span with id '{}' on workspaceId '{}'", id, workspaceId); + return Response.noContent().build(); } @@ -162,10 +195,14 @@ public Response update(@PathParam("id") UUID id, @ApiResponse(responseCode = "204", description = "No Content")}) public Response deleteById(@PathParam("id") UUID id) { + log.info("Deleting trace with id '{}'", id); + service.delete(id) .contextWrite(ctx -> setRequestContext(ctx, requestContext)) .block(); + log.info("Deleted trace with id '{}'", id); + return Response.noContent().build(); } @@ -176,10 +213,16 @@ public Response deleteById(@PathParam("id") UUID id) { public Response addTraceFeedbackScore(@PathParam("id") UUID id, @RequestBody(content = @Content(schema = @Schema(implementation = FeedbackScore.class))) @NotNull @Valid FeedbackScore score) { + String workspaceId = requestContext.get().getWorkspaceId(); + + log.info("Add span feedback score '{}' for id '{}' on workspaceId '{}'", score.name(), id, workspaceId); + feedbackScoreService.scoreTrace(id, score) .contextWrite(ctx -> setRequestContext(ctx, requestContext)) .block(); + log.info("Added span feedback score '{}' for id '{}' on workspaceId '{}'", score.name(), id, workspaceId); + return Response.noContent().build(); } @@ -190,10 +233,16 @@ public Response addTraceFeedbackScore(@PathParam("id") UUID id, public Response deleteTraceFeedbackScore(@PathParam("id") UUID id, @RequestBody(content = @Content(schema = @Schema(implementation = DeleteFeedbackScore.class))) @NotNull @Valid DeleteFeedbackScore score) { + String workspaceId = requestContext.get().getWorkspaceId(); + + log.info("Delete span feedback score '{}' for id '{}' on workspaceId '{}'", score.name(), id, workspaceId); + feedbackScoreService.deleteTraceScore(id, score.name()) .contextWrite(ctx -> setRequestContext(ctx, requestContext)) .block(); + log.info("Deleted span feedback score '{}' for id '{}' on workspaceId '{}'", score.name(), id, workspaceId); + return Response.noContent().build(); } @@ -204,11 +253,17 @@ public Response deleteTraceFeedbackScore(@PathParam("id") UUID id, public Response scoreBatchOfTraces( @RequestBody(content = @Content(schema = @Schema(implementation = FeedbackScoreBatch.class))) @NotNull @Valid FeedbackScoreBatch batch) { + String workspaceId = requestContext.get().getWorkspaceId(); + + log.info("Feedback scores batch for traces, size {} on workspaceId '{}'", batch.scores().size(), workspaceId); + feedbackScoreService.scoreBatchOfTraces(batch.scores()) .contextWrite(ctx -> setRequestContext(ctx, requestContext)) .retryWhen(AsyncUtils.handleConnectionError()) .block(); + log.info("Feedback scores batch for traces, size {} on workspaceId '{}'", batch.scores().size(), workspaceId); + return Response.noContent().build(); } diff --git a/apps/opik-backend/src/main/java/com/comet/opik/domain/DatasetDAO.java b/apps/opik-backend/src/main/java/com/comet/opik/domain/DatasetDAO.java index 714b9738c3..c3fc5a9c64 100644 --- a/apps/opik-backend/src/main/java/com/comet/opik/domain/DatasetDAO.java +++ b/apps/opik-backend/src/main/java/com/comet/opik/domain/DatasetDAO.java @@ -76,7 +76,4 @@ List find(@Bind("limit") int limit, @SqlQuery("SELECT * FROM datasets WHERE workspace_id = :workspace_id AND name = :name") Optional findByName(@Bind("workspace_id") String workspaceId, @Bind("name") String name); - @SqlQuery("SELECT workspace_id FROM datasets WHERE id = :id") - String getWorkspaceId(@Bind("id") UUID id); - } diff --git a/apps/opik-backend/src/main/java/com/comet/opik/domain/DatasetItemService.java b/apps/opik-backend/src/main/java/com/comet/opik/domain/DatasetItemService.java index f35048b4db..da5b70fee9 100644 --- a/apps/opik-backend/src/main/java/com/comet/opik/domain/DatasetItemService.java +++ b/apps/opik-backend/src/main/java/com/comet/opik/domain/DatasetItemService.java @@ -82,7 +82,7 @@ private Mono getDatasetId(DatasetItemBatch batch) { Dataset dataset = datasetService.findById(batch.datasetId(), workspaceId); if (dataset == null) { - throw throwsConflict( + throw newConflict( "workspace_name from dataset item batch and dataset_id from item does not match"); } @@ -92,10 +92,12 @@ private Mono getDatasetId(DatasetItemBatch batch) { } private Throwable failWithError(String error) { + log.info(error); return new ClientErrorException(Response.status(422).entity(new ErrorMessage(List.of(error))).build()); } - private ClientErrorException throwsConflict(String error) { + private ClientErrorException newConflict(String error) { + log.info(error); return new ClientErrorException(Response.status(409).entity(new ErrorMessage(List.of(error))).build()); } @@ -172,10 +174,12 @@ private List addIdIfAbsent(DatasetItemBatch batch) { } private Mono failWithConflict(String message) { + log.info(message); return Mono.error(new IdentifierMismatchException(new ErrorMessage(List.of(message)))); } private NotFoundException failWithNotFound(String message) { + log.info(message); return new NotFoundException(message, Response.status(Response.Status.NOT_FOUND).entity(new ErrorMessage(List.of(message))).build()); } diff --git a/apps/opik-backend/src/main/java/com/comet/opik/domain/DatasetService.java b/apps/opik-backend/src/main/java/com/comet/opik/domain/DatasetService.java index c0b5c610c7..041be369ad 100644 --- a/apps/opik-backend/src/main/java/com/comet/opik/domain/DatasetService.java +++ b/apps/opik-backend/src/main/java/com/comet/opik/domain/DatasetService.java @@ -55,8 +55,6 @@ public interface DatasetService { void delete(UUID id); DatasetPage find(int page, int size, DatasetCriteria criteria); - - String getWorkspaceId(UUID id); } @Singleton @@ -64,6 +62,8 @@ public interface DatasetService { @Slf4j class DatasetServiceImpl implements DatasetService { + private static final String DATASET_ALREADY_EXISTS = "Dataset already exists"; + private final @NonNull IdGenerator idGenerator; private final @NonNull TransactionTemplate template; private final @NonNull Provider requestContext; @@ -95,7 +95,8 @@ public Dataset save(@NonNull Dataset dataset) { return dao.findById(newDataset.id(), workspaceId).orElseThrow(); } catch (UnableToExecuteStatementException e) { if (e.getCause() instanceof SQLIntegrityConstraintViolationException) { - throw new EntityAlreadyExistsException(new ErrorMessage(List.of("Dataset already exists"))); + log.info(DATASET_ALREADY_EXISTS); + throw new EntityAlreadyExistsException(new ErrorMessage(List.of(DATASET_ALREADY_EXISTS))); } else { throw e; } @@ -110,6 +111,7 @@ public UUID getOrCreate(@NonNull String workspaceId, @NonNull String name, @NonN if (dataset.isEmpty()) { UUID id = idGenerator.generateId(); + log.info("Creating dataset with id '{}', name '{}', workspaceId '{}'", id, name, workspaceId); template.inTransaction(WRITE, handle -> { handle.attach(DatasetDAO.class) .save( @@ -125,6 +127,7 @@ public UUID getOrCreate(@NonNull String workspaceId, @NonNull String name, @NonN log.info("Created dataset with id '{}', name '{}', workspaceId '{}'", id, name, workspaceId); return id; } + UUID id = dataset.get().id(); log.info("Got dataset with id '{}', name '{}', workspaceId '{}'", id, name, workspaceId); return id; @@ -146,7 +149,8 @@ public void update(@NonNull UUID id, @NonNull DatasetUpdate dataset) { } } catch (UnableToExecuteStatementException e) { if (e.getCause() instanceof SQLIntegrityConstraintViolationException) { - throw new EntityAlreadyExistsException(new ErrorMessage(List.of("Dataset already exists"))); + log.info(DATASET_ALREADY_EXISTS); + throw new EntityAlreadyExistsException(new ErrorMessage(List.of(DATASET_ALREADY_EXISTS))); } else { throw e; } @@ -226,6 +230,7 @@ public void delete(@NonNull DatasetIdentifier identifier) { private NotFoundException newNotFoundException() { String message = "Dataset not found"; + log.info(message); return new NotFoundException(message, Response.status(Response.Status.NOT_FOUND).entity(new ErrorMessage(List.of(message))).build()); } @@ -273,10 +278,4 @@ public DatasetPage find(int page, int size, DatasetCriteria criteria) { .toList(), page, datasets.size(), count); }); } - - @Override - public String getWorkspaceId(UUID id) { - return template.inTransaction(READ_ONLY, handle -> handle.attach(DatasetDAO.class).getWorkspaceId(id)); - } - } diff --git a/apps/opik-backend/src/main/java/com/comet/opik/domain/ExperimentItemService.java b/apps/opik-backend/src/main/java/com/comet/opik/domain/ExperimentItemService.java index 51e15d26ea..0967e25793 100644 --- a/apps/opik-backend/src/main/java/com/comet/opik/domain/ExperimentItemService.java +++ b/apps/opik-backend/src/main/java/com/comet/opik/domain/ExperimentItemService.java @@ -27,7 +27,7 @@ public class ExperimentItemService { private final @NonNull ExperimentService experimentService; private final @NonNull DatasetItemDAO datasetItemDAO; - public Mono create(Set experimentItems) { + public Mono create(@NonNull Set experimentItems) { Preconditions.checkArgument(CollectionUtils.isNotEmpty(experimentItems), "Argument 'experimentItems' must not be empty"); @@ -69,12 +69,15 @@ private void validateExperimentsWorkspace(Set experimentItems, S .block()); if (!allExperimentsBelongToWorkspace) { - throw new ClientErrorException( - "Upserting experiment item with 'experiment_id' not belonging to the workspace", - Response.Status.CONFLICT); + throw createConflict("Upserting experiment item with 'experiment_id' not belonging to the workspace"); } } + private ClientErrorException createConflict(String message) { + log.info(message); + return new ClientErrorException(message, Response.Status.CONFLICT); + } + private void validateDatasetItemsWorkspace(Set experimentItems, String workspaceId) { Set datasetItemIds = experimentItems .stream() @@ -87,9 +90,7 @@ private void validateDatasetItemsWorkspace(Set experimentItems, .block()); if (!allDatasetItemsBelongToWorkspace) { - throw new ClientErrorException( - "Upserting experiment item with 'dataset_item_id' not belonging to the workspace", - Response.Status.CONFLICT); + throw createConflict("Upserting experiment item with 'dataset_item_id' not belonging to the workspace"); } } @@ -110,7 +111,9 @@ public Mono get(@NonNull UUID id) { } private NotFoundException newNotFoundException(UUID id) { - return new NotFoundException("Not found experiment item with id '%s'".formatted(id)); + String message = "Not found experiment item with id '%s'".formatted(id); + log.info(message); + return new NotFoundException(message); } public Mono delete(@NonNull Set ids) { diff --git a/apps/opik-backend/src/main/java/com/comet/opik/domain/ExperimentService.java b/apps/opik-backend/src/main/java/com/comet/opik/domain/ExperimentService.java index 7383c141f6..6cb15f7273 100644 --- a/apps/opik-backend/src/main/java/com/comet/opik/domain/ExperimentService.java +++ b/apps/opik-backend/src/main/java/com/comet/opik/domain/ExperimentService.java @@ -117,12 +117,15 @@ private Mono handleCreateError(Throwable throwable, UUID id) { } private ClientErrorException newConflictException(UUID id) { - return new ClientErrorException("Already exists experiment with id '%s'".formatted(id), - Response.Status.CONFLICT); + String message = "Already exists experiment with id '%s'".formatted(id); + log.info(message); + return new ClientErrorException(message, Response.Status.CONFLICT); } private NotFoundException newNotFoundException(UUID id) { - return new NotFoundException("Not found experiment with id '%s'".formatted(id)); + String message = "Not found experiment with id '%s'".formatted(id); + log.info(message); + return new NotFoundException(message); } public Mono validateExperimentWorkspace(@NonNull String workspaceId, @NonNull Set experimentIds) { diff --git a/apps/opik-backend/src/main/java/com/comet/opik/domain/FeedbackDefinitionDAO.java b/apps/opik-backend/src/main/java/com/comet/opik/domain/FeedbackDefinitionDAO.java index a7332c8a98..ecfef9c028 100644 --- a/apps/opik-backend/src/main/java/com/comet/opik/domain/FeedbackDefinitionDAO.java +++ b/apps/opik-backend/src/main/java/com/comet/opik/domain/FeedbackDefinitionDAO.java @@ -64,7 +64,4 @@ List> find(@Bind("limit") int limit, @Bind("workspaceId") String workspaceId, @Define("name") @Bind("name") String name, @Define("type") @Bind("type") FeedbackType type); - - @SqlQuery("SELECT workspace_id FROM feedback_definitions WHERE id = :id") - String getWorkspaceId(@Bind("id") UUID id); } diff --git a/apps/opik-backend/src/main/java/com/comet/opik/domain/FeedbackDefinitionService.java b/apps/opik-backend/src/main/java/com/comet/opik/domain/FeedbackDefinitionService.java index e7ba341649..afe5e86273 100644 --- a/apps/opik-backend/src/main/java/com/comet/opik/domain/FeedbackDefinitionService.java +++ b/apps/opik-backend/src/main/java/com/comet/opik/domain/FeedbackDefinitionService.java @@ -14,6 +14,7 @@ import jakarta.ws.rs.core.Response; import lombok.NonNull; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.jdbi.v3.core.statement.UnableToExecuteStatementException; import ru.vyarus.guicey.jdbi3.tx.TransactionTemplate; @@ -36,14 +37,15 @@ public interface FeedbackDefinitionService { > T get(UUID id); Page> find(int page, int size, FeedbackDefinitionCriteria criteria); - - String getWorkspaceId(UUID id); } +@Slf4j @Singleton @RequiredArgsConstructor(onConstructor_ = @Inject) class FeedbackDefinitionServiceImpl implements FeedbackDefinitionService { + private static final String FEEDBACK_ALREADY_EXISTS = "Feedback already exists"; + private final @NonNull TransactionTemplate template; private final @NonNull IdGenerator generator; private final @NonNull Provider requestContext; @@ -75,14 +77,6 @@ public Page> find(int page, int size, @NonNull FeedbackDef }); } - @Override - public String getWorkspaceId(UUID id) { - return template.inTransaction(READ_ONLY, handle -> { - var repository = handle.attach(FeedbackDefinitionDAO.class); - return repository.getWorkspaceId(id); - }); - } - @Override @SuppressWarnings("unchecked") public > T get(@NonNull UUID id) { @@ -145,7 +139,8 @@ public > T create(@NonNull T feedback) { } catch (UnableToExecuteStatementException e) { if (e.getCause() instanceof SQLIntegrityConstraintViolationException) { - throw new EntityAlreadyExistsException(new ErrorMessage(List.of("Feedback already exists"))); + log.info(FEEDBACK_ALREADY_EXISTS); + throw new EntityAlreadyExistsException(new ErrorMessage(List.of(FEEDBACK_ALREADY_EXISTS))); } else { throw e; } @@ -181,7 +176,8 @@ public > T update(@NonNull UUID id, @NonNull }); } catch (UnableToExecuteStatementException e) { if (e.getCause() instanceof SQLIntegrityConstraintViolationException) { - throw new EntityAlreadyExistsException(new ErrorMessage(List.of("Feedback already exists"))); + log.info(FEEDBACK_ALREADY_EXISTS); + throw new EntityAlreadyExistsException(new ErrorMessage(List.of(FEEDBACK_ALREADY_EXISTS))); } else { throw e; } @@ -201,6 +197,7 @@ public void delete(@NonNull UUID id) { private NotFoundException createNotFoundError() { String message = "Feedback definition not found"; + log.info(message); return new NotFoundException(message, Response.status(Response.Status.NOT_FOUND).entity(new ErrorMessage(List.of(message))).build()); } diff --git a/apps/opik-backend/src/main/java/com/comet/opik/domain/FeedbackScoreService.java b/apps/opik-backend/src/main/java/com/comet/opik/domain/FeedbackScoreService.java index 6cb1084da8..3c2569ba61 100644 --- a/apps/opik-backend/src/main/java/com/comet/opik/domain/FeedbackScoreService.java +++ b/apps/opik-backend/src/main/java/com/comet/opik/domain/FeedbackScoreService.java @@ -260,6 +260,7 @@ public Mono deleteTraceScore(UUID id, String name) { } private Mono failWithNotFound(String errorMessage) { + log.info(errorMessage); return Mono.error(new NotFoundException(Response.status(404) .entity(new ErrorMessage(List.of(errorMessage))).build())); } @@ -269,12 +270,16 @@ private Mono extractResult(Long rowsUpdated) { } private Throwable failWithTraceNotFound(UUID id) { + String message = "Trace id: %s not found".formatted(id); + log.info(message); return new NotFoundException(Response.status(404) - .entity(new ErrorMessage(List.of("Trace id: %s not found".formatted(id)))).build()); + .entity(new ErrorMessage(List.of(message))).build()); } private NotFoundException failWithSpanNotFound(UUID id) { - return new NotFoundException("Not found span with id '%s'".formatted(id)); + String message = "Not found span with id '%s'".formatted(id); + log.info(message); + return new NotFoundException(message); } } diff --git a/apps/opik-backend/src/main/java/com/comet/opik/domain/ProjectDAO.java b/apps/opik-backend/src/main/java/com/comet/opik/domain/ProjectDAO.java index dc3ad537cc..fdfb236857 100644 --- a/apps/opik-backend/src/main/java/com/comet/opik/domain/ProjectDAO.java +++ b/apps/opik-backend/src/main/java/com/comet/opik/domain/ProjectDAO.java @@ -70,7 +70,4 @@ default Optional fetch(UUID id, String workspaceId) { @SqlQuery("SELECT * FROM projects WHERE workspace_id = :workspaceId AND name IN ()") List findByNames(@Bind("workspaceId") String workspaceId, @BindList("names") Collection names); - - @SqlQuery("SELECT workspace_id FROM projects WHERE id = :id") - String getWorkspaceId(@Bind("id") UUID id); } diff --git a/apps/opik-backend/src/main/java/com/comet/opik/domain/ProjectService.java b/apps/opik-backend/src/main/java/com/comet/opik/domain/ProjectService.java index 2ad62fd022..043d6e5a5e 100644 --- a/apps/opik-backend/src/main/java/com/comet/opik/domain/ProjectService.java +++ b/apps/opik-backend/src/main/java/com/comet/opik/domain/ProjectService.java @@ -16,6 +16,7 @@ import jakarta.ws.rs.core.Response; import lombok.NonNull; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.jdbi.v3.core.statement.UnableToExecuteStatementException; import ru.vyarus.guicey.jdbi3.tx.TransactionTemplate; @@ -50,20 +51,21 @@ public interface ProjectService { List findByNames(String workspaceId, List names); Project getOrCreate(String workspaceId, String projectName, String userName); - - String getWorkspaceId(UUID id); } +@Slf4j @Singleton @RequiredArgsConstructor(onConstructor_ = @Inject) class ProjectServiceImpl implements ProjectService { + private static final String PROJECT_ALREADY_EXISTS = "Project already exists"; private final @NonNull TransactionTemplate template; private final @NonNull IdGenerator idGenerator; private final @NonNull Provider requestContext; - private static NotFoundException createNotFoundError() { + private NotFoundException createNotFoundError() { String message = "Project not found"; + log.info(message); return new NotFoundException(message, Response.status(Response.Status.NOT_FOUND).entity(new ErrorMessage(List.of(message))).build()); } @@ -97,13 +99,18 @@ private Project createProject(Project project, UUID projectId, String userName, }); } catch (UnableToExecuteStatementException e) { if (e.getCause() instanceof SQLIntegrityConstraintViolationException) { - throw new EntityAlreadyExistsException(new ErrorMessage(List.of("Project already exists"))); + throw newConflict(); } else { throw e; } } } + private EntityAlreadyExistsException newConflict() { + log.info(PROJECT_ALREADY_EXISTS); + return new EntityAlreadyExistsException(new ErrorMessage(List.of(PROJECT_ALREADY_EXISTS))); + } + @Override public Project update(@NonNull UUID id, @NonNull ProjectUpdate projectUpdate) { String userName = requestContext.get().getUserName(); @@ -115,7 +122,7 @@ public Project update(@NonNull UUID id, @NonNull ProjectUpdate projectUpdate) { var repository = handle.attach(ProjectDAO.class); Project project = repository.fetch(id, workspaceId) - .orElseThrow(ProjectServiceImpl::createNotFoundError); + .orElseThrow(this::createNotFoundError); repository.update(project.id(), workspaceId, @@ -128,7 +135,7 @@ public Project update(@NonNull UUID id, @NonNull ProjectUpdate projectUpdate) { } catch (UnableToExecuteStatementException e) { if (e.getCause() instanceof SQLIntegrityConstraintViolationException) { - throw new EntityAlreadyExistsException(new ErrorMessage(List.of("Project already exists"))); + throw newConflict(); } else { throw e; } @@ -148,7 +155,7 @@ public Project get(@NonNull UUID id, @NonNull String workspaceId) { var repository = handle.attach(ProjectDAO.class); - return repository.fetch(id, workspaceId).orElseThrow(ProjectServiceImpl::createNotFoundError); + return repository.fetch(id, workspaceId).orElseThrow(this::createNotFoundError); }); } @@ -168,6 +175,7 @@ public void delete(@NonNull UUID id) { if (project.get().name().equalsIgnoreCase(DEFAULT_PROJECT)) { var message = "Cannot delete default project"; + log.info(message); throw new CannotDeleteProjectException(new ErrorMessage(List.of(message))); } @@ -214,25 +222,22 @@ public List findByNames(String workspaceId, List names) { public Project getOrCreate(@NonNull String workspaceId, @NonNull String projectName, @NonNull String userName) { return findByNames(workspaceId, List.of(projectName)) - .stream().findFirst() + .stream() + .findFirst() .orElseGet(() -> { + log.info("Creating project with name '{}' on workspaceId '{}'", projectName, workspaceId); var project = Project.builder() .name(projectName) .build(); - var projectId = idGenerator.generateId(); + UUID projectId = idGenerator.generateId(); - return createProject(project, projectId, userName, workspaceId); + project = createProject(project, projectId, userName, workspaceId); + + log.info("Created project with id '{}', name '{}' on workspaceId '{}'", projectId, projectName, + workspaceId); + return project; }); } - @Override - public String getWorkspaceId(UUID id) { - return template.inTransaction(READ_ONLY, handle -> { - - var repository = handle.attach(ProjectDAO.class); - - return repository.getWorkspaceId(id); - }); - } } diff --git a/apps/opik-backend/src/main/java/com/comet/opik/domain/SpanService.java b/apps/opik-backend/src/main/java/com/comet/opik/domain/SpanService.java index 5f0c4fdf4e..27caa0053f 100644 --- a/apps/opik-backend/src/main/java/com/comet/opik/domain/SpanService.java +++ b/apps/opik-backend/src/main/java/com/comet/opik/domain/SpanService.java @@ -235,10 +235,13 @@ private Mono updateOrFail(SpanUpdate spanUpdate, UUID id, Span existingSpa } private NotFoundException newNotFoundException(UUID id) { - return new NotFoundException("Not found span with id '%s'".formatted(id)); + String message = "Not found span with id '%s'".formatted(id); + log.info(message); + return new NotFoundException(message); } private Mono failWithConflict(String error) { + log.info(error); return Mono.error(new IdentifierMismatchException(new ErrorMessage(List.of(error)))); } diff --git a/apps/opik-backend/src/main/java/com/comet/opik/domain/TraceService.java b/apps/opik-backend/src/main/java/com/comet/opik/domain/TraceService.java index 77002bf5ca..1b3b70a556 100644 --- a/apps/opik-backend/src/main/java/com/comet/opik/domain/TraceService.java +++ b/apps/opik-backend/src/main/java/com/comet/opik/domain/TraceService.java @@ -22,6 +22,7 @@ import jakarta.ws.rs.core.Response; import lombok.NonNull; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.core.scheduler.Schedulers; @@ -55,6 +56,7 @@ public interface TraceService { } +@Slf4j @Singleton @RequiredArgsConstructor(onConstructor_ = @Inject) class TraceServiceImpl implements TraceService { @@ -251,10 +253,12 @@ private Mono getProjectByName(String projectName) { } private Mono failWithConflict(String error) { + log.info(error); return Mono.error(new IdentifierMismatchException(new ErrorMessage(List.of(error)))); } private NotFoundException failWithNotFound(String error) { + log.info(error); return new NotFoundException(Response.status(404).entity(new ErrorMessage(List.of(error))).build()); }