diff --git a/apps/opik-backend/config.yml b/apps/opik-backend/config.yml index b36b5d486d..6d5660b947 100644 --- a/apps/opik-backend/config.yml +++ b/apps/opik-backend/config.yml @@ -74,8 +74,9 @@ rateLimit: limit: ${RATE_LIMIT_GENERAL_EVENTS_LIMIT:-10000} durationInSeconds: ${RATE_LIMIT_GENERAL_EVENTS_DURATION_IN_SEC:-60} +usageReport: + enabled: ${OPIK_USAGE_REPORT_ENABLED:-true} + url: ${OPIK_USAGE_REPORT_URL:-https://stats.comet.com/notify/event/} + metadata: version: ${OPIK_VERSION:-latest} - usageReport: - enabled: ${OPIK_REPORTING_ENABLED:-true} - url: ${OPIK_REPORTING_URL:-https://stats.comet.com/notify/event/} diff --git a/apps/opik-backend/src/main/java/com/comet/opik/OpikApplication.java b/apps/opik-backend/src/main/java/com/comet/opik/OpikApplication.java index 77c463b1e7..6b1de8b643 100644 --- a/apps/opik-backend/src/main/java/com/comet/opik/OpikApplication.java +++ b/apps/opik-backend/src/main/java/com/comet/opik/OpikApplication.java @@ -7,6 +7,7 @@ import com.comet.opik.infrastructure.db.DatabaseAnalyticsModule; import com.comet.opik.infrastructure.db.IdGeneratorModule; import com.comet.opik.infrastructure.db.NameGeneratorModule; +import com.comet.opik.infrastructure.http.HttpModule; import com.comet.opik.infrastructure.ratelimit.RateLimitModule; import com.comet.opik.infrastructure.redis.RedisModule; import com.comet.opik.utils.JsonBigDecimalDeserializer; @@ -62,7 +63,7 @@ public void initialize(Bootstrap bootstrap) { .bundles(JdbiBundle.forDatabase((conf, env) -> conf.getDatabase()) .withPlugins(new SqlObjectPlugin(), new Jackson2Plugin())) .modules(new DatabaseAnalyticsModule(), new IdGeneratorModule(), new AuthModule(), new RedisModule(), - new RateLimitModule(), new NameGeneratorModule()) + new RateLimitModule(), new NameGeneratorModule(), new HttpModule()) .listen(new ApplicationStartupListener()) .enableAutoConfig() .build()); diff --git a/apps/opik-backend/src/main/java/com/comet/opik/infrastructure/OpikMetadataConfig.java b/apps/opik-backend/src/main/java/com/comet/opik/infrastructure/MetadataConfig.java similarity index 55% rename from apps/opik-backend/src/main/java/com/comet/opik/infrastructure/OpikMetadataConfig.java rename to apps/opik-backend/src/main/java/com/comet/opik/infrastructure/MetadataConfig.java index 0daf83d5b3..36d37716f7 100644 --- a/apps/opik-backend/src/main/java/com/comet/opik/infrastructure/OpikMetadataConfig.java +++ b/apps/opik-backend/src/main/java/com/comet/opik/infrastructure/MetadataConfig.java @@ -6,16 +6,10 @@ import lombok.Data; @Data -public class OpikMetadataConfig { - - public record UsageReport(@Valid @JsonProperty boolean enabled, @Valid @JsonProperty String url) { - } +public class MetadataConfig { @Valid @JsonProperty @NotNull private String version; - @Valid - @NotNull @JsonProperty - private UsageReport usageReport; } diff --git a/apps/opik-backend/src/main/java/com/comet/opik/infrastructure/OpikConfiguration.java b/apps/opik-backend/src/main/java/com/comet/opik/infrastructure/OpikConfiguration.java index 4ac2b7d943..0de199be3d 100644 --- a/apps/opik-backend/src/main/java/com/comet/opik/infrastructure/OpikConfiguration.java +++ b/apps/opik-backend/src/main/java/com/comet/opik/infrastructure/OpikConfiguration.java @@ -40,5 +40,9 @@ public class OpikConfiguration extends Configuration { @Valid @NotNull @JsonProperty - private OpikMetadataConfig metadata = new OpikMetadataConfig(); + private MetadataConfig metadata = new MetadataConfig(); + + @Valid + @NotNull @JsonProperty + private UsageReportConfig usageReport = new UsageReportConfig(); } diff --git a/apps/opik-backend/src/main/java/com/comet/opik/infrastructure/UsageReportConfig.java b/apps/opik-backend/src/main/java/com/comet/opik/infrastructure/UsageReportConfig.java new file mode 100644 index 0000000000..ff476caea2 --- /dev/null +++ b/apps/opik-backend/src/main/java/com/comet/opik/infrastructure/UsageReportConfig.java @@ -0,0 +1,18 @@ +package com.comet.opik.infrastructure; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import lombok.Data; + +@Data +public class UsageReportConfig { + + @Valid + @JsonProperty + private boolean enabled; + + @Valid + @JsonProperty + private String url; + +} diff --git a/apps/opik-backend/src/main/java/com/comet/opik/infrastructure/bi/ApplicationStartupListener.java b/apps/opik-backend/src/main/java/com/comet/opik/infrastructure/bi/ApplicationStartupListener.java index b0b7026a52..d839a534e4 100644 --- a/apps/opik-backend/src/main/java/com/comet/opik/infrastructure/bi/ApplicationStartupListener.java +++ b/apps/opik-backend/src/main/java/com/comet/opik/infrastructure/bi/ApplicationStartupListener.java @@ -1,39 +1,20 @@ package com.comet.opik.infrastructure.bi; -import com.comet.opik.domain.IdGenerator; -import com.comet.opik.infrastructure.OpikConfiguration; -import com.comet.opik.infrastructure.lock.LockService; import com.google.inject.Injector; -import jakarta.ws.rs.client.Client; -import jakarta.ws.rs.client.ClientBuilder; -import jakarta.ws.rs.client.Entity; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; -import reactor.core.publisher.Mono; -import reactor.core.scheduler.Schedulers; import ru.vyarus.dropwizard.guice.module.lifecycle.GuiceyLifecycle; import ru.vyarus.dropwizard.guice.module.lifecycle.GuiceyLifecycleListener; import ru.vyarus.dropwizard.guice.module.lifecycle.event.GuiceyLifecycleEvent; import ru.vyarus.dropwizard.guice.module.lifecycle.event.InjectorPhaseEvent; -import java.net.URI; -import java.util.Map; -import java.util.Optional; import java.util.concurrent.atomic.AtomicReference; -import static com.comet.opik.infrastructure.lock.LockService.Lock; - @Slf4j @RequiredArgsConstructor public class ApplicationStartupListener implements GuiceyLifecycleListener { - public static final String NOTIFICATION_EVENT_TYPE = "opik_os_startup_be"; - // This event cannot depend on authentication - private final Client client = ClientBuilder.newClient(); private final AtomicReference injector = new AtomicReference<>(); @Override @@ -44,104 +25,10 @@ public void onEvent(GuiceyLifecycleEvent event) { } if (event.getType() == GuiceyLifecycle.ApplicationStarted) { + var installationReportService = injector.get().getInstance(InstallationReportService.class); - String eventType = GuiceyLifecycle.ApplicationStarted.name(); - - var config = (OpikConfiguration) event.getSharedState().getConfiguration().get(); - - if (!config.getMetadata().getUsageReport().enabled()) { - log.info("Usage report is disabled"); - return; - } - - if (StringUtils.isEmpty(config.getMetadata().getUsageReport().url())) { - log.warn("Usage report URL is not set"); - return; - } - - var lockService = injector.get().getInstance(LockService.class); - var generator = injector.get().getInstance(IdGenerator.class); - var usageReport = injector.get().getInstance(UsageReportDAO.class); - - var lock = new Lock("opik-%s".formatted(eventType)); - - lockService.executeWithLock(lock, tryToReportStartupEvent(usageReport, generator, eventType, config)) - .subscribeOn(Schedulers.boundedElastic()) - .onErrorResume(e -> { - log.warn("Didn't reported due to error", e); - return Mono.empty(); - }).block(); + installationReportService.reportInstallation(); } } - private Mono tryToReportStartupEvent(UsageReportDAO usageReport, IdGenerator generator, String eventType, - OpikConfiguration config) { - return Mono.fromCallable(() -> { - - String anonymousId = getAnonymousId(usageReport, generator); - - log.info("Anonymous ID: {}", anonymousId); - - if (usageReport.isEventReported(eventType)) { - log.info("Event already reported"); - return null; - } - - reportEvent(anonymousId, eventType, config, usageReport); - return null; - }); - } - - private String getAnonymousId(UsageReportDAO usageReport, IdGenerator generator) { - var anonymousId = usageReport.getAnonymousId(); - - if (anonymousId.isEmpty()) { - log.info("Anonymous ID not found, generating a new one"); - var newId = generator.generateId(); - log.info("Generated new ID: {}", newId); - - // Save the new ID - usageReport.saveAnonymousId(newId.toString()); - - anonymousId = Optional.of(newId.toString()); - } - - return anonymousId.get(); - } - - private void reportEvent(String anonymousId, String eventType, OpikConfiguration config, - UsageReportDAO usageReport) { - - usageReport.addEvent(eventType); - - var startupEvent = new OpikStartupEvent( - anonymousId, - NOTIFICATION_EVENT_TYPE, - Map.of("opik_app_version", config.getMetadata().getVersion())); - - try (Response response = client.target(URI.create(config.getMetadata().getUsageReport().url())) - .request() - .accept(MediaType.APPLICATION_JSON_TYPE) - .post(Entity.json(startupEvent))) { - - if (response.getStatusInfo().getFamily() == Response.Status.Family.SUCCESSFUL && response.hasEntity()) { - - var notificationEventResponse = response.readEntity(NotificationEventResponse.class); - - if (notificationEventResponse.success()) { - usageReport.markEventAsReported(eventType); - log.info("Event reported successfully: {}", notificationEventResponse.message()); - } else { - log.warn("Failed to report event: {}", notificationEventResponse.message()); - } - - return; - } - - log.warn("Failed to report event: {}", response.getStatusInfo()); - if (response.hasEntity()) { - log.warn("Response: {}", response.readEntity(String.class)); - } - } - } } diff --git a/apps/opik-backend/src/main/java/com/comet/opik/infrastructure/bi/InstallationReportService.java b/apps/opik-backend/src/main/java/com/comet/opik/infrastructure/bi/InstallationReportService.java new file mode 100644 index 0000000000..d60181a959 --- /dev/null +++ b/apps/opik-backend/src/main/java/com/comet/opik/infrastructure/bi/InstallationReportService.java @@ -0,0 +1,135 @@ +package com.comet.opik.infrastructure.bi; + +import com.comet.opik.domain.IdGenerator; +import com.comet.opik.infrastructure.OpikConfiguration; +import com.comet.opik.infrastructure.lock.LockService; +import com.google.inject.ImplementedBy; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.Entity; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import reactor.core.publisher.Mono; +import reactor.core.scheduler.Schedulers; +import ru.vyarus.dropwizard.guice.module.lifecycle.GuiceyLifecycle; + +import java.net.URI; +import java.util.Map; +import java.util.Optional; + +@ImplementedBy(InstallationReportServiceImpl.class) +interface InstallationReportService { + String NOTIFICATION_EVENT_TYPE = "opik_os_startup_be"; + + void reportInstallation(); +} + +@Singleton +@Slf4j +@RequiredArgsConstructor(onConstructor_ = @Inject) +class InstallationReportServiceImpl implements InstallationReportService { + + private final LockService lockService; + private final IdGenerator generator; + private final UsageReportService usageReport; + private final OpikConfiguration config; + private final Client client; + + public void reportInstallation() { + + String eventType = GuiceyLifecycle.ApplicationStarted.name(); + + if (!config.getUsageReport().isEnabled()) { + log.info("Usage report is disabled"); + return; + } + + if (StringUtils.isEmpty(config.getUsageReport().getUrl())) { + log.warn("Usage report URL is not set"); + return; + } + + var lock = new LockService.Lock("opik-%s".formatted(eventType)); + + lockService.executeWithLock(lock, tryToReportStartupEvent(eventType)) + .subscribeOn(Schedulers.boundedElastic()) + .onErrorResume(e -> { + log.warn("Didn't reported due to error", e); + return Mono.empty(); + }).block(); + + } + + private Mono tryToReportStartupEvent(String eventType) { + return Mono.fromCallable(() -> { + + String anonymousId = getAnonymousId(); + + log.info("Anonymous ID: {}", anonymousId); + + if (usageReport.isEventReported(eventType)) { + log.info("Event already reported"); + return null; + } + + reportEvent(anonymousId, eventType); + return null; + }); + } + + private String getAnonymousId() { + var anonymousId = usageReport.getAnonymousId(); + + if (anonymousId.isEmpty()) { + log.info("Anonymous ID not found, generating a new one"); + var newId = generator.generateId(); + log.info("Generated new ID: {}", newId); + + // Save the new ID + usageReport.saveAnonymousId(newId.toString()); + + anonymousId = Optional.of(newId.toString()); + } + + return anonymousId.get(); + } + + private void reportEvent(String anonymousId, String eventType) { + + usageReport.addEvent(eventType); + + var startupEvent = new OpikStartupEvent( + anonymousId, + NOTIFICATION_EVENT_TYPE, + Map.of("opik_app_version", config.getMetadata().getVersion())); + + try (Response response = client.target(URI.create(config.getUsageReport().getUrl())) + .request() + .accept(MediaType.APPLICATION_JSON_TYPE) + .post(Entity.json(startupEvent))) { + + if (response.getStatusInfo().getFamily() == Response.Status.Family.SUCCESSFUL && response.hasEntity()) { + + var notificationEventResponse = response.readEntity(NotificationEventResponse.class); + + if (notificationEventResponse.success()) { + usageReport.markEventAsReported(eventType); + log.info("Event reported successfully: {}", notificationEventResponse.message()); + } else { + log.warn("Failed to report event: {}", notificationEventResponse.message()); + } + + return; + } + + log.warn("Failed to report event: {}", response.getStatusInfo()); + if (response.hasEntity()) { + log.warn("Response: {}", response.readEntity(String.class)); + } + } + } +} diff --git a/apps/opik-backend/src/main/java/com/comet/opik/infrastructure/bi/MetadataDAO.java b/apps/opik-backend/src/main/java/com/comet/opik/infrastructure/bi/MetadataDAO.java new file mode 100644 index 0000000000..35e0881a69 --- /dev/null +++ b/apps/opik-backend/src/main/java/com/comet/opik/infrastructure/bi/MetadataDAO.java @@ -0,0 +1,16 @@ +package com.comet.opik.infrastructure.bi; + +import org.jdbi.v3.sqlobject.customizer.Bind; +import org.jdbi.v3.sqlobject.statement.SqlQuery; +import org.jdbi.v3.sqlobject.statement.SqlUpdate; + +import java.util.Optional; + +interface MetadataDAO { + + @SqlQuery("SELECT value FROM metadata WHERE `key` = :key") + Optional getMetadataKey(@Bind("key") String key); + + @SqlUpdate("INSERT INTO metadata (`key`, value) VALUES (:key, :value)") + void saveMetadataKey(@Bind("key") String key, @Bind("value") String value); +} diff --git a/apps/opik-backend/src/main/java/com/comet/opik/infrastructure/bi/NotificationEventResponse.java b/apps/opik-backend/src/main/java/com/comet/opik/infrastructure/bi/NotificationEventResponse.java index de87a4f3a3..d0f20ee40f 100644 --- a/apps/opik-backend/src/main/java/com/comet/opik/infrastructure/bi/NotificationEventResponse.java +++ b/apps/opik-backend/src/main/java/com/comet/opik/infrastructure/bi/NotificationEventResponse.java @@ -1,6 +1,5 @@ package com.comet.opik.infrastructure.bi; - import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.databind.PropertyNamingStrategies; import com.fasterxml.jackson.databind.annotation.JsonNaming; diff --git a/apps/opik-backend/src/main/java/com/comet/opik/infrastructure/bi/UsageReportDAO.java b/apps/opik-backend/src/main/java/com/comet/opik/infrastructure/bi/UsageReportDAO.java index 9e6dce5d95..bd21d34d99 100644 --- a/apps/opik-backend/src/main/java/com/comet/opik/infrastructure/bi/UsageReportDAO.java +++ b/apps/opik-backend/src/main/java/com/comet/opik/infrastructure/bi/UsageReportDAO.java @@ -1,80 +1,18 @@ package com.comet.opik.infrastructure.bi; -import com.google.inject.ImplementedBy; -import jakarta.inject.Inject; -import jakarta.inject.Singleton; -import lombok.NonNull; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.jdbi.v3.core.Jdbi; -import org.jdbi.v3.core.statement.UnableToExecuteStatementException; +import org.jdbi.v3.sqlobject.customizer.Bind; +import org.jdbi.v3.sqlobject.statement.SqlQuery; +import org.jdbi.v3.sqlobject.statement.SqlUpdate; -import java.sql.SQLIntegrityConstraintViolationException; -import java.util.Optional; - -@ImplementedBy(UsageReportDAOImpl.class) interface UsageReportDAO { - Optional getAnonymousId(); - - void saveAnonymousId(@NonNull String id); - - boolean isEventReported(@NonNull String eventType); - - void addEvent(@NonNull String eventType); - - void markEventAsReported(@NonNull String eventType); -} - -@Slf4j -@RequiredArgsConstructor(onConstructor_ = @Inject) -@Singleton -class UsageReportDAOImpl implements UsageReportDAO { - - private final Jdbi jdbi; - - public Optional getAnonymousId() { - return jdbi.inTransaction(handle -> handle.createQuery("SELECT value FROM metadata WHERE `key` = :key") - .bind("key", Metadata.anonymous_id) - .mapTo(String.class) - .findFirst()); - } - - public void saveAnonymousId(@NonNull String id) { - jdbi.useHandle(handle -> handle.createUpdate("INSERT INTO metadata (`key`, value) VALUES (:key, :value)") - .bind("key", Metadata.anonymous_id) - .bind("value", id) - .execute()); - } + @SqlQuery("SELECT COUNT(*) > 0 FROM usage_information WHERE event_type = :eventType AND reported_at IS NOT NULL") + boolean isEventReported(@Bind("eventType") String eventType); - public boolean isEventReported(@NonNull String eventType) { - return jdbi.inTransaction(handle -> handle.createQuery( - "SELECT COUNT(*) > 0 FROM usage_information WHERE event_type = :eventType AND reported_at IS NOT NULL") - .bind("eventType", eventType) - .mapTo(Boolean.class) - .one()); - } + @SqlUpdate("INSERT INTO usage_information (event_type) VALUES (:eventType)") + int addEvent(@Bind("eventType") String eventType); - public void addEvent(@NonNull String eventType) { - try { - jdbi.useHandle( - handle -> handle.createUpdate("INSERT INTO usage_information (event_type) VALUES (:eventType)") - .bind("eventType", eventType) - .execute()); - } catch (UnableToExecuteStatementException e) { - if (e.getCause() instanceof SQLIntegrityConstraintViolationException) { - log.warn("Event type already exists: {}", eventType); - } else { - log.error("Failed to add event", e); - } - } - } + @SqlUpdate("UPDATE usage_information SET reported_at = NOW() WHERE event_type = :eventType") + int markEventAsReported(@Bind("eventType") String eventType); - public void markEventAsReported(@NonNull String eventType) { - jdbi.useHandle(handle -> handle - .createUpdate( - "UPDATE usage_information SET reported_at = current_timestamp(6) WHERE event_type = :eventType") - .bind("eventType", eventType) - .execute()); - } } diff --git a/apps/opik-backend/src/main/java/com/comet/opik/infrastructure/bi/UsageReportService.java b/apps/opik-backend/src/main/java/com/comet/opik/infrastructure/bi/UsageReportService.java new file mode 100644 index 0000000000..17fcae3a68 --- /dev/null +++ b/apps/opik-backend/src/main/java/com/comet/opik/infrastructure/bi/UsageReportService.java @@ -0,0 +1,77 @@ +package com.comet.opik.infrastructure.bi; + +import com.google.inject.ImplementedBy; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; +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; + +import java.sql.SQLIntegrityConstraintViolationException; +import java.util.Optional; + +import static com.comet.opik.infrastructure.db.TransactionTemplate.READ_ONLY; +import static com.comet.opik.infrastructure.db.TransactionTemplate.WRITE; + +@ImplementedBy(UsageReportServiceImpl.class) +interface UsageReportService { + + Optional getAnonymousId(); + + void saveAnonymousId(@NonNull String id); + + boolean isEventReported(@NonNull String eventType); + + void addEvent(@NonNull String eventType); + + void markEventAsReported(@NonNull String eventType); +} + +@Slf4j +@RequiredArgsConstructor(onConstructor_ = @Inject) +@Singleton +class UsageReportServiceImpl implements UsageReportService { + + private final @NonNull TransactionTemplate template; + + public Optional getAnonymousId() { + return template.inTransaction(READ_ONLY, + handle -> handle.attach(MetadataDAO.class).getMetadataKey(Metadata.anonymous_id.name())); + } + + public void saveAnonymousId(@NonNull String id) { + template.inTransaction(WRITE, handle -> { + handle.attach(MetadataDAO.class).saveMetadataKey(Metadata.anonymous_id.name(), id); + return null; + }); + } + + public boolean isEventReported(@NonNull String eventType) { + return template.inTransaction(READ_ONLY, + handle -> handle.attach(UsageReportDAO.class).isEventReported(eventType)); + } + + public void addEvent(@NonNull String eventType) { + try { + template.inTransaction(WRITE, handle -> { + handle.attach(UsageReportDAO.class).addEvent(eventType); + return null; + }); + } catch (UnableToExecuteStatementException e) { + if (e.getCause() instanceof SQLIntegrityConstraintViolationException) { + log.warn("Event type already exists: {}", eventType); + } else { + log.error("Failed to add event", e); + } + } + } + + public void markEventAsReported(@NonNull String eventType) { + template.inTransaction(WRITE, handle -> { + handle.attach(UsageReportDAO.class).markEventAsReported(eventType); + return null; + }); + } +} \ No newline at end of file diff --git a/apps/opik-backend/src/main/java/com/comet/opik/infrastructure/http/HttpModule.java b/apps/opik-backend/src/main/java/com/comet/opik/infrastructure/http/HttpModule.java new file mode 100644 index 0000000000..c3e650fb48 --- /dev/null +++ b/apps/opik-backend/src/main/java/com/comet/opik/infrastructure/http/HttpModule.java @@ -0,0 +1,17 @@ +package com.comet.opik.infrastructure.http; + +import com.google.inject.AbstractModule; +import com.google.inject.Provides; +import jakarta.inject.Singleton; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.ClientBuilder; + +public class HttpModule extends AbstractModule { + + @Provides + @Singleton + public Client client() { + return ClientBuilder.newClient(); + } + +} diff --git a/apps/opik-backend/src/main/resources/liquibase/db-app-state/migrations/000002_create_usage_usage_information_table.sql b/apps/opik-backend/src/main/resources/liquibase/db-app-state/migrations/000002_create_usage_usage_information_table.sql index 803e661f12..06f1659275 100644 --- a/apps/opik-backend/src/main/resources/liquibase/db-app-state/migrations/000002_create_usage_usage_information_table.sql +++ b/apps/opik-backend/src/main/resources/liquibase/db-app-state/migrations/000002_create_usage_usage_information_table.sql @@ -10,6 +10,7 @@ CREATE TABLE metadata ( CREATE TABLE usage_information ( event_type VARCHAR(255) NOT NULL, + created_at TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), last_updated_at TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), reported_at TIMESTAMP(6) DEFAULT NULL, PRIMARY KEY `usage_information_pk` (event_type) diff --git a/apps/opik-backend/src/test/java/com/comet/opik/api/resources/utils/TestDropwizardAppExtensionUtils.java b/apps/opik-backend/src/test/java/com/comet/opik/api/resources/utils/TestDropwizardAppExtensionUtils.java index 9adc03f1bc..35d5920300 100644 --- a/apps/opik-backend/src/test/java/com/comet/opik/api/resources/utils/TestDropwizardAppExtensionUtils.java +++ b/apps/opik-backend/src/test/java/com/comet/opik/api/resources/utils/TestDropwizardAppExtensionUtils.java @@ -159,10 +159,10 @@ public void run(GuiceyEnvironment environment) { } if (appContextConfig.usageReportEnabled()) { - list.add("metadata.usageReport.enabled: true"); + list.add("usageReport.enabled: true"); if (appContextConfig.usageReportUrl() != null) { - list.add("metadata.usageReport.url: %s".formatted(appContextConfig.usageReportUrl())); + list.add("usageReport.url: %s".formatted(appContextConfig.usageReportUrl())); } } diff --git a/apps/opik-backend/src/test/java/com/comet/opik/infrastructure/bi/ApplicationStartupListenerTest.java b/apps/opik-backend/src/test/java/com/comet/opik/infrastructure/bi/ApplicationStartupListenerTest.java index 52d2431885..470291e6bf 100644 --- a/apps/opik-backend/src/test/java/com/comet/opik/infrastructure/bi/ApplicationStartupListenerTest.java +++ b/apps/opik-backend/src/test/java/com/comet/opik/infrastructure/bi/ApplicationStartupListenerTest.java @@ -87,7 +87,7 @@ class FirstStartupTest { .withRequestBody(matchingJsonPath("$.anonymous_id", matching( "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"))) .withRequestBody(matchingJsonPath("$.event_type", - matching(ApplicationStartupListener.NOTIFICATION_EVENT_TYPE))) + matching(InstallationReportService.NOTIFICATION_EVENT_TYPE))) .withRequestBody(matchingJsonPath("$.event_properties.opik_app_version", matching(VERSION))) .willReturn(WireMock.okJson(SUCCESS_RESPONSE))); @@ -103,11 +103,11 @@ class FirstStartupTest { } @Test - void shouldNotifyEvent(UsageReportDAO reportDAO) { + void shouldNotifyEvent(UsageReportService usageReportService) { wireMock.server().verify(postRequestedFor(urlPathEqualTo("/v1/notify/event"))); - Assertions.assertTrue(reportDAO.isEventReported(GuiceyLifecycle.ApplicationStarted.name())); - Assertions.assertTrue(reportDAO.getAnonymousId().isPresent()); + Assertions.assertTrue(usageReportService.isEventReported(GuiceyLifecycle.ApplicationStarted.name())); + Assertions.assertTrue(usageReportService.getAnonymousId().isPresent()); } } @@ -166,11 +166,11 @@ class SecondStartupTest { } @Test - void shouldNotNotifyEvent(UsageReportDAO reportDAO) { + void shouldNotNotifyEvent(UsageReportService usageReportService) { wireMock.server().verify(exactly(0), postRequestedFor(urlPathEqualTo("/v1/notify/event"))); - Assertions.assertTrue(reportDAO.isEventReported(GuiceyLifecycle.ApplicationStarted.name())); - Assertions.assertTrue(reportDAO.getAnonymousId().isPresent()); + Assertions.assertTrue(usageReportService.isEventReported(GuiceyLifecycle.ApplicationStarted.name())); + Assertions.assertTrue(usageReportService.getAnonymousId().isPresent()); } } diff --git a/apps/opik-backend/src/test/resources/config-test.yml b/apps/opik-backend/src/test/resources/config-test.yml index 619da6572a..2346f9f56a 100644 --- a/apps/opik-backend/src/test/resources/config-test.yml +++ b/apps/opik-backend/src/test/resources/config-test.yml @@ -69,7 +69,8 @@ server: rateLimit: enabled: false +usageReport: + enabled: false + metadata: version: ${OPIK_VERSION:-latest} - usageReport: - enabled: false \ No newline at end of file