diff --git a/.changeset/long-cherries-eat.md b/.changeset/long-cherries-eat.md
new file mode 100644
index 000000000..d30268628
--- /dev/null
+++ b/.changeset/long-cherries-eat.md
@@ -0,0 +1,5 @@
+---
+"app-avatax": patch
+---
+
+Remove feature flag for client logs. After this change logs are enabled by default.
diff --git a/apps/avatax/.env.example b/apps/avatax/.env.example
index d80acf660..cbdcdd49e 100644
--- a/apps/avatax/.env.example
+++ b/apps/avatax/.env.example
@@ -34,11 +34,12 @@ SECRET_KEY=
# E2E_USER_PASSWORD=
-FF_ENABLE_EXPERIMENTAL_LOGS=true
-DYNAMODB_LOGS_ITEM_TTL_IN_DAYS=30
+# DYNAMODB_LOGS_ITEM_TTL_IN_DAYS=14 - time to live for logs in DynamoDB
DYNAMODB_LOGS_TABLE_NAME=avatax-client-logs
AWS_REGION=localhost
AWS_ENDPOINT_URL=http://localhost:8000
+AWS_ACCESS_KEY_ID=...
+AWS_SECRET_ACCESS_KEY=...
-MANIFEST_APP_ID=saleor.app.avatax
\ No newline at end of file
+MANIFEST_APP_ID=saleor.app.avatax
diff --git a/apps/avatax/src/env.ts b/apps/avatax/src/env.ts
index abecb1109..435956520 100644
--- a/apps/avatax/src/env.ts
+++ b/apps/avatax/src/env.ts
@@ -19,15 +19,13 @@ export const env = createEnv({
APP_IFRAME_BASE_URL: z.string().optional(),
APP_LOG_LEVEL: z.enum(["fatal", "error", "warn", "info", "debug", "trace"]).default("info"),
AVATAX_CLIENT_TIMEOUT: z.coerce.number().optional().default(15000),
- // TODO: make them required once we remove `FF_ENABLE_EXPERIMENTAL_LOGS`
- AWS_ACCESS_KEY_ID: z.string().optional(),
- AWS_REGION: z.string().optional(),
- AWS_SECRET_ACCESS_KEY: z.string().optional(),
- DYNAMODB_LOGS_ITEM_TTL_IN_DAYS: z.coerce.number().optional(),
- DYNAMODB_LOGS_TABLE_NAME: z.string().optional(),
+ AWS_ACCESS_KEY_ID: z.string(),
+ AWS_REGION: z.string(),
+ AWS_SECRET_ACCESS_KEY: z.string(),
+ DYNAMODB_LOGS_ITEM_TTL_IN_DAYS: z.coerce.number().positive().optional().default(14),
+ DYNAMODB_LOGS_TABLE_NAME: z.string(),
E2E_USER_NAME: z.string().optional(),
E2E_USER_PASSWORD: z.string().optional(),
- FF_ENABLE_EXPERIMENTAL_LOGS: booleanSchema.optional().default("false"),
FILE_APL_PATH: z.string().optional(),
MANIFEST_APP_ID: z.string().optional().default("saleor.app.avatax"),
OTEL_ENABLED: booleanSchema.optional().default("false"),
@@ -59,7 +57,6 @@ export const env = createEnv({
E2E_USER_NAME: process.env.E2E_USER_NAME,
E2E_USER_PASSWORD: process.env.E2E_USER_PASSWORD,
ENV: process.env.ENV,
- FF_ENABLE_EXPERIMENTAL_LOGS: process.env.FF_ENABLE_EXPERIMENTAL_LOGS,
FILE_APL_PATH: process.env.FILE_APL_PATH,
MANIFEST_APP_ID: process.env.MANIFEST_APP_ID,
NEXT_PUBLIC_SENTRY_DSN: process.env.NEXT_PUBLIC_SENTRY_DSN,
diff --git a/apps/avatax/src/modules/client-logs/client-logs-feature-config.ts b/apps/avatax/src/modules/client-logs/client-logs-feature-config.ts
deleted file mode 100644
index 016667c3b..000000000
--- a/apps/avatax/src/modules/client-logs/client-logs-feature-config.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-import { z } from "zod";
-
-import { env } from "@/env";
-
-const schema = z
- .object({
- isEnabled: z.boolean({ coerce: true }).optional().default(false),
- dynamoTableName: z.string().optional(),
- ttlInDays: z
- .number({
- coerce: true,
- errorMap(issue) {
- return { message: "Provide value in days" };
- },
- })
- .optional()
- .default(30),
- })
- .superRefine((values, ctx) => {
- if (values.isEnabled === true) {
- if (!values.dynamoTableName) {
- ctx.addIssue({
- code: "custom",
- message: "When logs are enabled, DYNAMODB_LOGS_TABLE_NAME must be provided",
- });
- }
- } else {
- return;
- }
- });
-
-export const clientLogsFeatureConfig = schema.parse({
- isEnabled: env.FF_ENABLE_EXPERIMENTAL_LOGS,
- dynamoTableName: env.DYNAMODB_LOGS_TABLE_NAME,
- ttlInDays: env.DYNAMODB_LOGS_ITEM_TTL_IN_DAYS,
-});
diff --git a/apps/avatax/src/modules/client-logs/client-logs.router.ts b/apps/avatax/src/modules/client-logs/client-logs.router.ts
index 4838f683c..9dd04b3d3 100644
--- a/apps/avatax/src/modules/client-logs/client-logs.router.ts
+++ b/apps/avatax/src/modules/client-logs/client-logs.router.ts
@@ -1,11 +1,8 @@
-import * as Sentry from "@sentry/nextjs";
import { TRPCError } from "@trpc/server";
-import { err, ok } from "neverthrow";
import { z } from "zod";
-import { createLogger } from "@/logger";
+import { env } from "@/env";
import { type ClientLogValue } from "@/modules/client-logs/client-log";
-import { clientLogsFeatureConfig } from "@/modules/client-logs/client-logs-feature-config";
import {
createLogsDocumentClient,
createLogsDynamoClient,
@@ -16,72 +13,41 @@ import { router } from "@/modules/trpc/trpc-server";
import { ClientLogDynamoEntityFactory, LogsTable } from "./dynamo-schema";
-// TODO: Remove this lazy method once feature is not behind feature flag
-const getLogsRepository = () => {
- const logger = createLogger("getLogsRepository");
-
- if (!clientLogsFeatureConfig.dynamoTableName) {
- logger.warn("DYNAMODB_LOGS_TABLE_NAME is not set.");
-
- return err(new Error("DYNAMODB_LOGS_TABLE_NAME is not set."));
- }
-
- const logsTable = LogsTable.create({
- documentClient: createLogsDocumentClient(createLogsDynamoClient()),
- tableName: clientLogsFeatureConfig.dynamoTableName,
- });
- const logByDateEntity = ClientLogDynamoEntityFactory.createLogByDate(logsTable);
- const logByCheckoutOrOrderId =
- ClientLogDynamoEntityFactory.createLogByCheckoutOrOrderId(logsTable);
-
- return ok(
- new LogsRepositoryDynamodb({
- logsTable,
- logByDateEntity,
- logByCheckoutOrOrderId: logByCheckoutOrOrderId,
- }),
- );
-};
-
-const procedureWithFlag = protectedClientProcedure.use(({ ctx, next }) => {
- if (!clientLogsFeatureConfig.isEnabled) {
- throw new TRPCError({
- cause: "Feature disabled",
- code: "FORBIDDEN",
- message: "Feature is disabled",
+const procedureWithLogsRepository = protectedClientProcedure.use(({ ctx, next }) => {
+ try {
+ const logsTable = LogsTable.create({
+ documentClient: createLogsDocumentClient(createLogsDynamoClient()),
+ tableName: env.DYNAMODB_LOGS_TABLE_NAME,
});
- }
-
- const logsRepositoryResult = getLogsRepository();
-
- if (logsRepositoryResult.isErr()) {
- Sentry.captureException(logsRepositoryResult.error);
-
+ const logByDateEntity = ClientLogDynamoEntityFactory.createLogByDate(logsTable);
+ const logByCheckoutOrOrderId =
+ ClientLogDynamoEntityFactory.createLogByCheckoutOrOrderId(logsTable);
+
+ return next({
+ ctx: {
+ ...ctx,
+ logsRepository: new LogsRepositoryDynamodb({
+ logsTable,
+ logByDateEntity,
+ logByCheckoutOrOrderId,
+ }),
+ },
+ });
+ } catch (e) {
throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
- message: "Logs unavailable, contact support",
+ message: "Logs are not available, contact Saleor support",
});
}
-
- return next({
- ctx: {
- ...ctx,
- logsRepository: logsRepositoryResult.value,
- },
- });
});
/**
- * TODO: Implement pagination
*
* Router that fetches logs in the frontend.
* To write log, use directly repository
*/
export const clientLogsRouter = router({
- isEnabled: protectedClientProcedure.query(({ ctx }) => {
- return clientLogsFeatureConfig.isEnabled;
- }),
- getByDate: procedureWithFlag
+ getByDate: procedureWithLogsRepository
.input(
z.object({
startDate: z.string().datetime(),
@@ -115,7 +81,7 @@ export const clientLogsRouter = router({
};
},
),
- getByCheckoutOrOrderId: procedureWithFlag
+ getByCheckoutOrOrderId: procedureWithLogsRepository
.input(
z.object({
checkoutOrOrderId: z.string(),
diff --git a/apps/avatax/src/modules/client-logs/dynamo-schema.ts b/apps/avatax/src/modules/client-logs/dynamo-schema.ts
index b0c324317..9ee876549 100644
--- a/apps/avatax/src/modules/client-logs/dynamo-schema.ts
+++ b/apps/avatax/src/modules/client-logs/dynamo-schema.ts
@@ -2,7 +2,7 @@ import { type DynamoDBDocumentClient } from "@aws-sdk/lib-dynamodb";
import { Entity, number, schema, string, Table } from "dynamodb-toolbox";
import { ulid } from "ulid";
-import { clientLogsFeatureConfig } from "@/modules/client-logs/client-logs-feature-config";
+import { env } from "@/env";
export class LogsTable extends Table<
{
@@ -61,7 +61,7 @@ export class LogsTable extends Table<
}
static getDefaultTTL() {
- const daysUntilExpire = clientLogsFeatureConfig.ttlInDays;
+ const daysUntilExpire = env.DYNAMODB_LOGS_ITEM_TTL_IN_DAYS;
const today = new Date();
// Add today + days until expire, export to UNIX epoch timestamp
diff --git a/apps/avatax/src/modules/client-logs/log-writer-factory.ts b/apps/avatax/src/modules/client-logs/log-writer-factory.ts
index 431616c5c..68e93c6c5 100644
--- a/apps/avatax/src/modules/client-logs/log-writer-factory.ts
+++ b/apps/avatax/src/modules/client-logs/log-writer-factory.ts
@@ -1,15 +1,11 @@
-import { clientLogsFeatureConfig } from "@/modules/client-logs/client-logs-feature-config";
+import { env } from "@/env";
+import { BaseError } from "@/error";
import {
createLogsDocumentClient,
createLogsDynamoClient,
} from "@/modules/client-logs/dynamo-client";
import { ClientLogDynamoEntityFactory, LogsTable } from "@/modules/client-logs/dynamo-schema";
-import {
- DynamoDbLogWriter,
- ILogWriter,
- LogWriterContext,
- NoopLogWriter,
-} from "@/modules/client-logs/log-writer";
+import { DynamoDbLogWriter, ILogWriter, LogWriterContext } from "@/modules/client-logs/log-writer";
import { LogsRepositoryDynamodb } from "@/modules/client-logs/logs-repository";
export interface ILogWriterFactory {
@@ -20,30 +16,31 @@ export interface ILogWriterFactory {
* Depending on static config, create an ILogWriter instance
*/
export class LogWriterFactory implements ILogWriterFactory {
- private createDynamoDbWriter(context: LogWriterContext): ILogWriter {
- const dynamoClient = createLogsDynamoClient();
- const logsTable = LogsTable.create({
- documentClient: createLogsDocumentClient(dynamoClient),
- tableName: clientLogsFeatureConfig.dynamoTableName!, // If not set, it will throw earlier
- });
- const repository = new LogsRepositoryDynamodb({
- logsTable,
- logByCheckoutOrOrderId: ClientLogDynamoEntityFactory.createLogByCheckoutOrOrderId(logsTable),
- logByDateEntity: ClientLogDynamoEntityFactory.createLogByDate(logsTable),
- });
+ static ErrorCreatingLogWriterError = BaseError.subclass("ErrorCreatingLogWriterError");
- return new DynamoDbLogWriter(repository, context);
- }
+ private createDynamoDbWriter(context: LogWriterContext): ILogWriter {
+ try {
+ const dynamoClient = createLogsDynamoClient();
+ const logsTable = LogsTable.create({
+ documentClient: createLogsDocumentClient(dynamoClient),
+ tableName: env.DYNAMODB_LOGS_TABLE_NAME,
+ });
+ const repository = new LogsRepositoryDynamodb({
+ logsTable,
+ logByCheckoutOrOrderId:
+ ClientLogDynamoEntityFactory.createLogByCheckoutOrOrderId(logsTable),
+ logByDateEntity: ClientLogDynamoEntityFactory.createLogByDate(logsTable),
+ });
- private createNoopWriter(): ILogWriter {
- return new NoopLogWriter();
+ return new DynamoDbLogWriter(repository, context);
+ } catch (e) {
+ throw new LogWriterFactory.ErrorCreatingLogWriterError("Failed to create DynamoDbLogWriter", {
+ cause: e,
+ });
+ }
}
createWriter(context: LogWriterContext): ILogWriter {
- if (clientLogsFeatureConfig.isEnabled) {
- return this.createDynamoDbWriter(context);
- } else {
- return this.createNoopWriter();
- }
+ return this.createDynamoDbWriter(context);
}
}
diff --git a/apps/avatax/src/pages/configuration.tsx b/apps/avatax/src/pages/configuration.tsx
index aaa0c6f83..d0677efa0 100644
--- a/apps/avatax/src/pages/configuration.tsx
+++ b/apps/avatax/src/pages/configuration.tsx
@@ -2,8 +2,6 @@ import { useAppBridge } from "@saleor/app-sdk/app-bridge";
import { Box, Button, Text } from "@saleor/macaw-ui";
import { useRouter } from "next/router";
-import { trpcClient } from "@/modules/trpc/trpc-client";
-
import { ChannelSection } from "../modules/channel-configuration/ui/channel-section";
import { ProvidersSection } from "../modules/provider-connections/ui/providers-section";
import { AppPageLayout } from "../modules/ui/app-page-layout";
@@ -11,7 +9,6 @@ import { Section } from "../modules/ui/app-section";
import { MatcherSection } from "../modules/ui/matcher-section";
const Header = () => {
- const { data: logsEnabled } = trpcClient.clientLogs.isEnabled.useQuery();
const { push } = useRouter();
return (
@@ -19,7 +16,7 @@ const Header = () => {
Configure the app by connecting to AvaTax. You can connect to multiple accounts.
- {logsEnabled && }
+
);
};
diff --git a/apps/avatax/src/pages/logs.tsx b/apps/avatax/src/pages/logs.tsx
index 344adf0cb..87a27bad2 100644
--- a/apps/avatax/src/pages/logs.tsx
+++ b/apps/avatax/src/pages/logs.tsx
@@ -1,6 +1,5 @@
import { useAppBridge } from "@saleor/app-sdk/app-bridge";
import { Box } from "@saleor/macaw-ui";
-import React from "react";
import { LogsBrowser } from "@/modules/client-logs/ui/logs-browser";
import { AppBreadcrumbs } from "@/modules/ui/app-breadcrumbs";
@@ -8,7 +7,7 @@ import { AppBreadcrumbs } from "@/modules/ui/app-breadcrumbs";
import { Section } from "../modules/ui/app-section";
const Header = () => {
- return Check App logs (up to last 100);
+ return Check App logs;
};
const ConfigurationPage = () => {
diff --git a/apps/avatax/src/setup-tests.ts b/apps/avatax/src/setup-tests.ts
index fff045cbc..b7dec1f94 100644
--- a/apps/avatax/src/setup-tests.ts
+++ b/apps/avatax/src/setup-tests.ts
@@ -2,6 +2,10 @@ import { vi } from "vitest";
vi.stubEnv("DYNAMODB_LOGS_ITEM_TTL_IN_DAYS", "7");
vi.stubEnv("SECRET_KEY", "test_secret_key");
+vi.stubEnv("DYNAMODB_LOGS_TABLE_NAME", "test-table");
+vi.stubEnv("AWS_REGION", "test");
+vi.stubEnv("AWS_ACCESS_KEY_ID", "test-id");
+vi.stubEnv("AWS_SECRET_ACCESS_KEY", "test-key");
/**
* Add test setup logic here