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

Add otel for vercel kv apl #335

Merged
merged 3 commits into from
Jan 4, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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/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
4 changes: 2 additions & 2 deletions 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 Expand Up @@ -273,7 +273,7 @@ export class SaleorCloudAPL implements APL {
debug("Saving data to SaleorCloudAPL for saleorApiUrl: %s", authData.saleorApiUrl);

return this.tracer.startActiveSpan(
"Call SaleorCloudAPL SET",
"SaleorCloudAPL.set",
{
attributes: {
saleorApiUrl: authData.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