Skip to content

Commit

Permalink
Add otel for vercel kv apl
Browse files Browse the repository at this point in the history
  • Loading branch information
lkostrowski committed Jan 4, 2024
1 parent 2f24478 commit 2dbfb83
Show file tree
Hide file tree
Showing 3 changed files with 128 additions and 29 deletions.
5 changes: 5 additions & 0 deletions .changeset/few-wolves-divide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@saleor/app-sdk": patch
---

Added OTEL for VercelKV APL. This APL is still experimental, so the change is marked as patch
2 changes: 1 addition & 1 deletion src/APL/saleor-cloud/saleor-cloud-apl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ export class SaleorCloudAPL implements APL {
debug("Will fetch data from SaleorCloudAPL for saleorApiUrl %s", saleorApiUrl);

return this.tracer.startActiveSpan(
"Call SaleorCloudAPL GET",
"SaleorCloudAPL.get",
{
attributes: {
saleorApiUrl,
Expand Down
150 changes: 122 additions & 28 deletions src/APL/vercel-kv/vercel-kv-apl.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { SpanKind, SpanStatusCode } from "@opentelemetry/api";
import { SemanticAttributes } from "@opentelemetry/semantic-conventions";
import { kv } from "@vercel/kv";

import { getOtelTracer, OTEL_APL_SERVICE_NAME } from "../../open-telemetry";
import { APL, AplConfiguredResult, AplReadyResult, AuthData } from "../apl";
import { createAPLDebug } from "../apl-debug";

Expand All @@ -10,6 +13,8 @@ type Params = {
export class VercelKvApl implements APL {
private debug = createAPLDebug("VercelKvApl");

private tracer = getOtelTracer();

/**
* Store all items inside hash collection, to enable read ALL items when needed.
* Otherwise, multiple redis calls will be needed to iterate over every key.
Expand All @@ -29,44 +34,133 @@ export class VercelKvApl implements APL {
async get(saleorApiUrl: string): Promise<AuthData | undefined> {
this.debug("Will call Vercel KV to get auth data for %s", saleorApiUrl);

try {
const authData = await kv.hget<AuthData>(this.hashCollectionKey, saleorApiUrl);

return authData ?? undefined;
} catch (e) {
this.debug("Failed to get auth data from Vercel KV");
this.debug(e);

throw e;
}
return this.tracer.startActiveSpan(
"VercelKvApl.get",
{
attributes: {
saleorApiUrl,
[SemanticAttributes.PEER_SERVICE]: OTEL_APL_SERVICE_NAME,
[SemanticAttributes.HTTP_METHOD]: "GET",
},
kind: SpanKind.CLIENT,
},
async (span) => {
try {
const authData = await kv.hget<AuthData>(this.hashCollectionKey, saleorApiUrl);

this.debug("Received response from VercelKV");

if (!authData) {
this.debug("AuthData is empty for %s", saleorApiUrl);
}

span
.setStatus({
code: 200,
message: "Received response from VercelKV",
})
.end();

return authData ?? undefined;
} catch (e) {
this.debug("Failed to get auth data from Vercel KV");
this.debug(e);

span.recordException("Failed to get auth data from Vercel KV");

span
.setStatus({
code: SpanStatusCode.ERROR,
message: "Failed to get auth data from Vercel KV",
})
.end();

throw e;
}
}
);
}

async set(authData: AuthData): Promise<void> {
this.debug("Will call Vercel KV to set auth data for %s", authData.saleorApiUrl);

try {
await kv.hset(this.hashCollectionKey, {
[authData.saleorApiUrl]: authData,
});
} catch (e) {
this.debug("Failed to set auth data in Vercel KV");
this.debug(e);

throw e;
}
return this.tracer.startActiveSpan(
"VercelKvApl.set",
{
attributes: {
saleorApiUrl: authData.saleorApiUrl,
[SemanticAttributes.PEER_SERVICE]: OTEL_APL_SERVICE_NAME,
[SemanticAttributes.HTTP_METHOD]: "POST",
},
kind: SpanKind.CLIENT,
},
async (span) => {
try {
await kv.hset(this.hashCollectionKey, {
[authData.saleorApiUrl]: authData,
});

span
.setStatus({
code: 200,
message: "Successfully written auth data to VercelKV",
})
.end();
} catch (e) {
this.debug("Failed to set auth data in Vercel KV");
this.debug(e);

span.recordException("Failed to set auth data in Vercel KV");
span
.setStatus({
code: SpanStatusCode.ERROR,
})
.end();

throw e;
}
}
);
}

async delete(saleorApiUrl: string) {
this.debug("Will call Vercel KV to delete auth data for %s", saleorApiUrl);

try {
await kv.hdel(this.hashCollectionKey, saleorApiUrl);
} catch (e) {
this.debug("Failed to delete auth data from Vercel KV");
this.debug(e);

throw e;
}
return this.tracer.startActiveSpan(
"VercelKvApl.delete",
{
attributes: {
saleorApiUrl,
[SemanticAttributes.PEER_SERVICE]: OTEL_APL_SERVICE_NAME,
[SemanticAttributes.HTTP_METHOD]: "DELETE",
},
kind: SpanKind.CLIENT,
},
async (span) => {
try {
await kv.hdel(this.hashCollectionKey, saleorApiUrl);

span
.setStatus({
code: 200,
message: "Successfully deleted auth data to VercelKV",
})
.end();
} catch (e) {
this.debug("Failed to delete auth data from Vercel KV");
this.debug(e);

span.recordException("Failed to delete auth data from Vercel KV");
span
.setStatus({
code: SpanStatusCode.ERROR,
})
.end();

throw e;
}
}
);
}

async getAll() {
Expand Down

0 comments on commit 2dbfb83

Please sign in to comment.