Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Enable client logs by default in AvaTax #1705

Merged
merged 2 commits into from
Jan 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/long-cherries-eat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"app-avatax": patch
---

Remove feature flag for client logs. After this change logs are enabled by default.
7 changes: 4 additions & 3 deletions apps/avatax/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -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
MANIFEST_APP_ID=saleor.app.avatax
13 changes: 5 additions & 8 deletions apps/avatax/src/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
Expand Down Expand Up @@ -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,
Expand Down

This file was deleted.

82 changes: 24 additions & 58 deletions apps/avatax/src/modules/client-logs/client-logs.router.ts
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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(),
Expand Down Expand Up @@ -115,7 +81,7 @@ export const clientLogsRouter = router({
};
},
),
getByCheckoutOrOrderId: procedureWithFlag
getByCheckoutOrOrderId: procedureWithLogsRepository
.input(
z.object({
checkoutOrOrderId: z.string(),
Expand Down
4 changes: 2 additions & 2 deletions apps/avatax/src/modules/client-logs/dynamo-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<
{
Expand Down Expand Up @@ -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
Expand Down
51 changes: 24 additions & 27 deletions apps/avatax/src/modules/client-logs/log-writer-factory.ts
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -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);
}
}
5 changes: 1 addition & 4 deletions apps/avatax/src/pages/configuration.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,21 @@ 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";
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 (
<Box display="flex" justifyContent="space-between">
<Section.Header>
Configure the app by connecting to AvaTax. You can connect to multiple accounts.
</Section.Header>
{logsEnabled && <Button onClick={() => push("/logs")}>Open Logs</Button>}
<Button onClick={() => push("/logs")}>Open Logs</Button>
</Box>
);
};
Expand Down
3 changes: 1 addition & 2 deletions apps/avatax/src/pages/logs.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
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";

import { Section } from "../modules/ui/app-section";

const Header = () => {
return <Section.Header>Check App logs (up to last 100)</Section.Header>;
return <Section.Header>Check App logs</Section.Header>;
};

const ConfigurationPage = () => {
Expand Down
4 changes: 4 additions & 0 deletions apps/avatax/src/setup-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading