Monitor a Node.js App with Datadog and Winston
Quickly set up error logging in SvelteKit or any another Node.js-based framework.
Sam Magura
Implementing error logging in your application is critical, because it allows you to take action on errors before your customers report them. And even if a customer does report an issue, you'll need error logs to get the context necessary to fix the issue.
In this post, we demonstrate how to log to Datadog , one of the leading cloud monitoring platforms. To do this, we'll create a Winston logger that sends events to Datadog. Once an event is logged, it will be visible in the Datadog cloud dashboard.
We'll implement this in a full stack SvelteKit app, though the same steps would be used for any app with a Node.js backend, such as Next.js or Express. The Datadog API key will be stored in Zero, and we'll use the Zero TypeScript SDK to fetch the API key at runtime.
🔗 The full code for this example is available in the zerosecrets/examples GitHub repository.
Secure your secrets conveniently
Zero is a modern secrets manager built with usability at its core. Reliable and secure, it saves time and effort.
Signing Up for Datadog
You can sign up for a Datadog free trial by clicking the "Get started free" button on the Datadog homepage . Even after the free trial expires, you can convert your account to a free plan to continue using the service.
Before continuing, we should create a Zero project to house the Datadog API key. Log in to Zero and create a new project, making sure to save the project's token to a safe location on your local PC.
Now, return to the Datadog console and navigate to the API keys page by hovering over your username in the bottom left corner. The link can be hard to find — see this docs page for a screenshot. Once you're on the API keys page, create an API key and copy it to your clipboard. Then, paste the API key into a new Zero secret like so:
Creating a SvelteKit App
Now that the Datadog API key is safely stored in Zero, we can proceed to create a barebones SvelteKit app to demonstrate the logging functionality. To bootstrap the app, run
npm create svelte@latest datadog-app
At the prompts, select "Skeleton project" and enable TypeScript.
Scaffolding the App
In this sample project, we are trying to log from the backend, so the frontend can simply be a button that calls the backend. To do this, we'll use a form action , one of the core features of SvelteKit. The frontend is simply an HTML form with a submit button, no JavaScript required:
<form method="POST">
<button>Submit action</button>
</form>
The corresponding server file, +page.server.ts
, will export a default action that throws an error. Once we have a logger, we'll update this code to log the error.
import {fail, type Actions} from '@sveltejs/kit'
export const actions: Actions = {
default: async (event) => {
try {
throw new Error('An error occurred.')
} catch (error: any) {
// TODO Log the error
return fail(500)
}
},
}
Fetching the API Key from Zero
Next, we'll integrate with Zero using the TypeScript SDK. Run
npm install @zerosecrets/zero @types/node
to install the requisite packages.
In a new file called lib/logger.ts
, we'll use the standard pattern for bringing down secrets from Zero:
import {zero} from '@zerosecrets/zero'
async function getSecrets() {
if (!process.env.ZERO_TOKEN) {
throw new Error('Did you forget to set the ZERO_TOKEN environment variable?')
}
try {
const result = await zero({
token: process.env.ZERO_TOKEN,
pick: ['datadog'],
callerName: 'production',
}).fetch()
return result?.datadog // { api_key: "your-datadog-api-key" }
} catch (error) {
console.error('Error fetching secrets from Zero:', error)
throw error
}
}
const secrets = await getSecrets()
if (!secrets || !secrets.api_key) {
throw new Error('Datadog API key not found in secrets.')
}
Creating the Winston Logger
Now, we'll set up a Winston logger with a transport that sends log events to Datadog, with the help of the datadog-winston npm package.
To proceed, install these packages:
npm i winston datadog-winston @types/datadog-winston
The code is very straightforward. If implementing this in a production app, you may wish to customize the ddtags
based on the environment your app is running in.
export const logger = winston.createLogger({
level: 'info',
transports: [
new DatadogWinston({
apiKey: secrets.api_key,
service: 'svelte-app',
ddsource: 'nodejs',
ddtags: 'env:staging,version:1.0.0',
}),
// new winston.transports.Console(),
],
})
Putting it All Together
To complete the app, update the server action to log the error with the Winston logger:
export const actions: Actions = {
default: async (event) => {
try {
throw new Error('An error occurred.')
} catch (error: any) {
logger.error(error.message, {stack: error.stack})
return fail(500)
}
},
}
Now, run the app with
ZERO_TOKEN='YOUR_ZERO_TOKEN' npm run dev
Open it in your browser and click the submit button that the app displays. Now, navigate to the Datadog console and select "Logs" from the main menu. You should see the error that the application created!
Conclusion
This post showed how straightforward it is to set up error logging to Datadog in a Node.js application with the help of Zero and Winston. That said, Datadog is an immensely powerful platform, and we really just scratched the surface of what it can do. You can go much further by capturing metrics in Datadog (e.g. CPU usage) and settings up custom dashboards and alarms.
Other articles
Using Notion as a Human-Readable Database
Capture form submissions from your web app and store them where your team works.
Managing Files in Amazon S3 from Node.js
Adding and removing files from S3 is a breeze with the AWS JavaScript SDK.
Secure your secrets
Zero is a modern secrets manager built with usability at its core. Reliable and secure, it saves time and effort.