# Logging | Remix Firebase SaaS Kit

> Logging is a fundamental part for your SaaS to understand and monitor the behavior of your code at runtime. Let's learn how to add logging to your Makerkit application.

*Canonical: https://makerkit.dev/docs/remix-fire/development/logging*

---

The Makerkit Boilerplate uses `pino` as logging library. Pino is simple and
lightweight, and it's used across the API functions to log important
information that helps you debug your code.

Generally speaking, you will find that we log every function, especially for
asynchronous operations that could fail for a number of reasons: network
issues, API exceptions, and so on.

So, how to log your API functions effectively? Our recommendation is to log
**before executing an operation** and then log the **result of the
operation**, without leaking important data.

Furthermore, we want to log information such as:
- which user is performing the operation?
- which organization is the user part of?
- any other information that can help you understand and debug what is
happening.

Let's assume you're writing an API function to write to your Firestore database:

```tsx
function addIntegrationHandler() {
  return writeToFirestore(data);
}
```

Let's rewrite the above by adding logging to your function:

```tsx
import logger from '~/core/logger';

async function addIntegrationHandler(
  userId: string,
  organizationId: number,
  integrationId: number,
) {
  // this is the context that every log will print out
  const loggingContext = {
    integrationId,
    organizationId,
    userId,
  };

  // Here we log what we're doing
  logger.log(loggingContext, `Adding new integration to organization`);

  try {
    await writeToFirestore(data);

    // Here we log that the result of the operation
    // was successful
    logger.log(loggingContext, `Integration successfully added`);

    // return successful response
    return res.json({
      integrationId,
      success: true
    });
  } catch (e) {
    // Here we log that the operation failed
    logger.error(loggingContext, `Encountered an error while adding integration`);

    // Logging errors can be okay but
    // ensure not to leak important information!
    logger.debug(e);

    // return 500
    return res.status(500).json({
      integrationId,
      success: false
    });
  }
}
```

If you use the filter `withExceptionFilter`, it will automatically
log eventual exceptions thrown by the function, which makes the try/catch
block optional.

NB: If you're using Vercel, logs are not persisted by default! [Check out the
Vercel integrations](https://vercel.com/integrations#logging) for adding persisting logs to your projects.
