Skip to content

Commit

Permalink
docs(recipe): add vercel (#3549)
Browse files Browse the repository at this point in the history
* docs(recipe): add vercel

* Update docs/docs/examples-tutorials/recipes/testing-vercel-functions-with-opentelemetry-tracetest.mdx

Co-authored-by: Julianne Fermi <julianne@kubeshop.io>

* Update docs/docs/examples-tutorials/recipes/testing-vercel-functions-with-opentelemetry-tracetest.mdx

Co-authored-by: Julianne Fermi <julianne@kubeshop.io>

---------

Co-authored-by: Julianne Fermi <julianne@kubeshop.io>
  • Loading branch information
adnanrahic and jfermi committed Jan 23, 2024
1 parent 2d6b79f commit c57a99b
Show file tree
Hide file tree
Showing 4 changed files with 345 additions and 1 deletion.
12 changes: 11 additions & 1 deletion docs/docs/examples-tutorials/recipes.mdx
Expand Up @@ -19,8 +19,10 @@ If you're already building something with Tracetest, explore these Recipes. They

These guides show integrations with other tools and vendors.

- [Trace-Based End to End Testing with Cypress and Tracetest](/tools-and-integrations/cypress)
- [Trace-Based End to End Testing with Playwright and Tracetest](/tools-and-integrations/playwright)
- [Running Tracetest with Testkube](/tools-and-integrations/testkube)
- [Running Tracetest with k6](/tools-and-integrations/k6)
- [Performance and Trace-Based Tests with Tracetest and k6](/tools-and-integrations/k6)
- [Running Tracetest Core with k6](/tools-and-integrations/k6-core)
- [Running Tracetest with Keptn](/tools-and-integrations/keptn)

Expand All @@ -30,6 +32,12 @@ These recipes show how to trigger Tracetest test runs with message queues like K

- [Testing Kafka in a Go API with OpenTelemetry](/examples-tutorials/recipes/testing-kafka-go-api-with-opentelemetry-tracetest)

## Serverless Functions (FaaS)

These recipes show how to run tests against Serverless Functions with Tracetest.

- [Testing Vercel Functions with OpenTelemetry](/examples-tutorials/recipes/testing-vercel-functions-with-opentelemetry-tracetest)

## Trace Data Stores

These recipes show integrations with trace data stores and tracing vendors/providers.
Expand Down Expand Up @@ -87,6 +95,8 @@ This integration point uses the OpenTelemetry Collector as a router to send trac

- [Sending traces to Sumo Logic from a Node.js app and fetching them from Sumo Logic with Tracetest](/examples-tutorials/recipes/running-tracetest-with-sumologic)



## CI/CD Automation

These guides show integrations with CI/CD tools.
Expand Down
@@ -0,0 +1,316 @@
---
id: testing-vercel-functions-with-opentelemetry-tracetest
title: Testing Vercel Functions (Next.js) with OpenTelemetry and Tracetest
description: Quick start on how to configure Vercel functions with OpenTelemetry and Tracetest for enhancing your integration tests with trace-based testing.
hide_table_of_contents: false
keywords:
- tracetest
- trace-based testing
- observability
- distributed tracing
- testing
- cypress
- end to end testing
- end-to-end testing
- integration testing
image: https://res.cloudinary.com/djwdcmwdz/image/upload/v1698686403/docs/Blog_Thumbnail_14_rsvkmo.jpg
---

:::note
[Check out the source code on GitHub here.](https://github.com/kubeshop/tracetest/tree/main/examples/integration-testing-vercel-functions)
:::

[Tracetest](https://tracetest.io/) is a testing tool based on [OpenTelemetry](https://opentelemetry.io/) that allows you to test your distributed application. It allows you to use data from distributed traces generated by OpenTelemetry to validate and assert if your application has the desired behavior defined by your test definitions.

[Vercel](https://vercel.com/) is a platform that hosts serverless functions and front-end code offering developers scalability and flexibility with no infrastructure overhead.

## Why is this important?

Testing Serverless Functions has been a pain point for years. Not having visibility into the infrastructure and not knowing where a test fails causes the MTTR to be higher than for other tools. Including OpenTelemetry in Vercel functions exposes telemetry that you can use for both production visibility and trace-based testing.

This sample shows how to run integration tests against Vercel Functions using [OpenTelemetry](https://opentelemetry.io/) and Tracetest.

The Vercel function will fetch data from an external API, transform the data and insert it into a Vercel Postgres database. This particular flow has two failure points that are difficult to test.

1. Validating that an external API request from a Vercel function is successful.
2. Validating that a Postgres insert request is successful.

## Prerequisites

**Tracetest Account**:

- Sign up to [`app.tracetest.io`](https://app.tracetest.io) or follow the [get started](/getting-started/installation) docs.
- Create an [environment](/concepts/environments).
- Create an [environment token](/concepts/environment-tokens).
- Have access to the environment's [agent API key](/configuration/agent).
- [Vercel Account](https://vercel.com/)
- [Vercel Postgres Database](https://vercel.com/docs/storage/vercel-postgres)

**Vercel Functions Example:**

Clone the official [Tracetest Pokeshop Demo App Repo](https://github.com/kubeshop/pokeshop) to your local machine.

```bash
git clone https://github.com/kubeshop/tracetest.git
cd tracetest/examples/integration-testing-vercel-functions
```

Before moving forward, run `npm i` in the root folder to install the dependencies.

```bash
npm i
```

**Docker**:

- Have [Docker](https://docs.docker.com/get-docker/) and [Docker Compose](https://docs.docker.com/compose/install/) installed on your machine.

## Project Structure

This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).

It's using Vercel Functions via `/pages/api`, with [OpenTelemetry configured as explained in the Vercel docs](https://nextjs.org/docs/pages/building-your-application/optimizing/open-telemetry#manual-opentelemetry-configuration).

### 1. Vercel (Next.js) Function

The `docker-compose.yaml` file reference the Next.js app with `next-app`.

### 2. Tracetest

The `docker-compose.yaml` file also has a Tracetest Agent service and an integration tests service.

### Docker Compose Network

All `services` in the `docker-compose.yaml` are on the same network and will be reachable by hostname from within other services. E.g. `next-app:3000` in the `test/api.pokemon.spec.docker.yaml` will map to the `next-app` service.

## Vercel (Next.js) Function

The Vercel Function is a simple API, [contained in the `pages/api/pokemon.ts` file](https://github.com/kubeshop/tracetest/blob/main/examples/integration-testing-vercel-functions/pages/api/pokemon.ts).

```typescript
import { trace, SpanStatusCode } from '@opentelemetry/api'
import type { NextApiRequest, NextApiResponse } from 'next'
import { sql } from '@vercel/postgres'

export async function addPokemon(pokemon: any) {
return await sql`
INSERT INTO pokemon (name)
VALUES (${pokemon.name})
RETURNING *;
`
}

export async function getPokemon(pokemon: any) {
return await sql`
SELECT * FROM pokemon where id=${pokemon.id};
`
}

export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
const activeSpan = trace.getActiveSpan()
const tracer = await trace.getTracer('integration-testing-vercel-functions')

try {

const externalPokemon = await tracer.startActiveSpan('GET Pokemon from pokeapi.co', async (externalPokemonSpan) => {
const requestUrl = `https://pokeapi.co/api/v2/pokemon/${req.body.id || '6'}`
const response = await fetch(requestUrl)
const { id, name } = await response.json()

externalPokemonSpan.setStatus({ code: SpanStatusCode.OK, message: String("Pokemon fetched successfully!") })
externalPokemonSpan.setAttribute('pokemon.name', name)
externalPokemonSpan.setAttribute('pokemon.id', id)
externalPokemonSpan.end()

return { id, name }
})

const addedPokemon = await tracer.startActiveSpan('Add Pokemon to Vercel Postgres', async (addedPokemonSpan) => {
const { rowCount, rows: [addedPokemon, ...rest] } = await addPokemon(externalPokemon)
addedPokemonSpan.setAttribute('pokemon.isAdded', rowCount === 1)
addedPokemonSpan.setAttribute('pokemon.added.name', addedPokemon.name)
addedPokemonSpan.end()
return addedPokemon
})

res.status(200).json(addedPokemon)

} catch (err) {
activeSpan?.setAttribute('error', String(err))
activeSpan?.recordException(String(err))
activeSpan?.setStatus({ code: SpanStatusCode.ERROR, message: String(err) })
res.status(500).json({ error: 'failed to load data' })
} finally {
activeSpan?.end()
}
}
```

The OpenTelemetry tracing is [contained in the `instrumentation.node.ts` file](https://github.com/kubeshop/tracetest/blob/main/examples/integration-testing-vercel-functions/instrumentation.node.ts). Traces will be sent to the Tracetest Agent.

```typescript
import { NodeSDK } from '@opentelemetry/sdk-node'
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'
import { Resource } from '@opentelemetry/resources'
import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions'
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node'
import { FetchInstrumentation } from '@opentelemetry/instrumentation-fetch'

const sdk = new NodeSDK({
// The OTEL_EXPORTER_OTLP_ENDPOINT env var is passed into "new OTLPTraceExporter" automatically.
// If the OTEL_EXPORTER_OTLP_ENDPOINT env var is not set the "new OTLPTraceExporter" will
// default to use "http://localhost:4317" for gRPC and "http://localhost:4318" for HTTP.
// This sample is using HTTP.
traceExporter: new OTLPTraceExporter(),
instrumentations: [
getNodeAutoInstrumentations(),
new FetchInstrumentation(),
],
resource: new Resource({
[SemanticResourceAttributes.SERVICE_NAME]: 'integration-testing-vercel-functions',
}),
})
sdk.start()
```

### Set up Environment Variables

Edit the `.env.development` file. Add your Vercel Postgres env vars.

```bash title=.env.development.local
# OTLP HTTP
OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4318"

# Vercel Postgres
POSTGRES_DATABASE="**********"
POSTGRES_HOST="**********"
POSTGRES_PASSWORD="**********"
POSTGRES_PRISMA_URL="**********"
POSTGRES_URL="**********"
POSTGRES_URL_NON_POOLING="**********"
POSTGRES_USER="**********"
```

### Start the Next.js Vercel Function

Spin up your Next.js app.

```bash
npm run dev
```

This starts the function on `http://localhost:3000/api/pokemon`.

## Testing the Vercel Function Locally

[Download the CLI](/getting-started/installation#install-the-tracetest-cli) for your operating system.

The CLI is bundled with [Tracetest Agent](/concepts/agent/) that runs in your infrastructure to collect responses and traces for tests.

To start Tracetest Agent add the `--api-key` from your environment.

```bash title=Terminal
tracetest start --api-key YOUR_AGENT_API_KEY
```

Run a test with the test definition `test/api.pokemon.spec.development.yaml`.

```yaml title=test/api.pokemon.spec.development.yaml
type: Test
spec:
id: kv8C-hOSR
name: Test API
trigger:
type: http
httpRequest:
method: POST
url: http://localhost:3000/api/pokemon
body: "{\n \"id\": \"6\"\n}"
headers:
- key: Content-Type
value: application/json
specs:
- selector: span[tracetest.span.type="http"]
name: "All HTTP Spans: Status code is 200"
assertions:
- attr:http.status_code = 200
```

```bash title=Terminal
tracetest run test -f ./test/api.pokemon.spec.development.yaml --required-gates test-specs --output pretty

[Output]
✔ Test API (https://app.tracetest.io/organizations/ttorg_e66318ba6544b856/environments/ttenv_0e807879e2e38d28/test/-gjd4idIR/run/22/test) - trace id: f2250362ff2f70f8f5be7b2fba74e4b2
✔ All HTTP Spans: Status code is 200
```

## Integration Testing the Vercel Function

Edit the `.env.docker` file to use your Vercel Postgres env vars.

```bash title=.env.docker
# OTLP HTTP
OTEL_EXPORTER_OTLP_ENDPOINT="http://tracetest-agent:4318"

# Vercel Postgres
POSTGRES_DATABASE="**********"
POSTGRES_HOST="**********"
POSTGRES_PASSWORD="**********"
POSTGRES_PRISMA_URL="**********"
POSTGRES_URL="**********"
POSTGRES_URL_NON_POOLING="**********"
POSTGRES_USER="**********"
```

This configures the `OTEL_EXPORTER_OTLP_ENDPOINT` to send traces to Tracetest Agent.

Edit the `docker-compose.yaml` in the root directory. Add your `TRACETEST_API_KEY`.

```yaml title=docker-compose.yaml
# [...]
tracetest-agent:
image: kubeshop/tracetest-agent:latest
environment:
- TRACETEST_API_KEY=YOUR_TRACETEST_API_KEY # Find the Agent API Key here: https://docs.tracetest.io/configuration/agent
ports:
- 4317:4317
- 4318:4318
networks:
- tracetest
```

Edit the `run.bash`. Add your `TRACETEST_API_TOKEN`.

```bash
#/bin/bash

# Find the API Token here: https://docs.tracetest.io/concepts/environment-tokens
tracetest configure -t YOUR_TRACETEST_API_TOKEN
tracetest run test -f ./api.pokemon.spec.docker.yaml --required-gates test-specs --output pretty
```

Now you can run the Vercel function and Tracetest Agent!

```bash
docker compose up -d --build
```

And, trigger the integration tests.

```bash
docker compose run integration-tests

[Ouput]
[+] Creating 1/0
✔ Container integration-testing-vercel-functions-tracetest-agent-1 Running 0.0s
SUCCESS Successfully configured Tracetest CLI
✔ Test API (https://app.tracetest.io/organizations/ttorg_e66318ba6544b856/environments/ttenv_82af376d61da80a0/test/p00W82OIR/run/8/test) - trace id: d64ab3a6f52a98141d26679fff3373b6
✔ All HTTP Spans: Status code is 200
```

## Learn More

Feel free to check out our [examples in GitHub](https://github.com/kubeshop/tracetest/tree/main/examples) and join our [Slack Community](https://dub.sh/tracetest-community) for more info!
7 changes: 7 additions & 0 deletions docs/docs/examples-tutorials/tutorials.mdx
Expand Up @@ -19,6 +19,7 @@ Check out the following blog posts with Tracetest-related content.

### Distributed Tracing Vendors

- [Sumo Logic and Tracetest: AI-Driven Observability Meets Testing](https://tracetest.io/blog/sumo-logic-and-tracetest-ai-driven-observability-meets-testing)
- [Tracetest + Dynatrace: Unified Observability for Testing](https://tracetest.io/blog/tracetest-dynatrace-unified-observability-for-testing)
- [Honeycomb + Tracetest: Observability-driven Development](https://tracetest.io/blog/honeycomb-tracetest-observability-driven-development)
- [Tracetest + Elastic: Trace-based testing meets APM](https://tracetest.io/blog/tracetest-integration-elastic-trace-based-testing-application-performance-monitoring)
Expand All @@ -34,6 +35,8 @@ Check out the following blog posts with Tracetest-related content.

### Tools

- [Cloud Native Observability and Cypress: An Unlikely Marriage](https://tracetest.io/blog/cloud-native-observability-and-cypress-an-unlikely-marriage)
- [Load Testing with k6 and Tracetest](https://tracetest.io/blog/load-testing-with-k6-and-tracetest)
- [Synthetic Monitoring with the Tracetest GitHub Action](https://tracetest.io/blog/synthetic-monitoring-with-the-tracetest-github-action)
- [Event-driven Kubernetes testing with Testkube and Tracetest](https://tracetest.io/blog/event-driven-kubernetes-testing-with-testkube-and-tracetest)
- [Announcing the Tracetest integration with Keptn](https://tracetest.io/blog/announcing-the-tracetest-integration-with-keptn-the-control-plane-for-cloud-native-application-life-cycle-orchestration)
Expand Down Expand Up @@ -61,6 +64,10 @@ Check out the following blog posts with Tracetest-related content.

- [Testing Event-driven Systems with OpenTelemetry](https://tracetest.io/blog/testing-event-driven-systems-with-opentelemetry)

### Testing Serverless Functions (Faas)

- [Integration Testing Vercel Serverless Functions with OpenTelemetry](https://tracetest.io/blog/integration-testing-vercel-serverless-functions-with-opentelemetry)

### Observability-driven development

- [Observability-driven development with Go and Tracetest](https://tracetest.io/blog/observability-driven-development-with-go-and-tracetest)
Expand Down
11 changes: 11 additions & 0 deletions docs/sidebars.js
Expand Up @@ -137,6 +137,17 @@ const sidebars = {
},
],
},
{
type: "category",
label: "Serverless Functions",
items: [
{
type: "doc",
id: "examples-tutorials/recipes/testing-vercel-functions-with-opentelemetry-tracetest",
label: "Testing Vercel Functions",
},
],
},
{
type: "category",
label: "OpenTelemetry",
Expand Down

0 comments on commit c57a99b

Please sign in to comment.