> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sqd.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Logging

> Configure Pino-compatible logging for a Solana Pipes SDK pipeline.

[solanaPortalStream()](../../reference/basic-components/source) accepts a Pino-compatible `logger`, so you can route pipeline logs to any Pino transport — GCP Cloud Logging, Sentry, or a local pretty-printer. Configure it once on the source; every transformer and target then receives the same instance as `ctx.logger`.

## Basic custom logger

Build a Pino transport, pass `pino(transport)` as the source's `logger`, and the whole pipeline logs through it:

```ts expandable theme={"system"}
import { createTarget } from "@subsquid/pipes";
import { solanaPortalStream, solanaQuery } from "@subsquid/pipes/solana";
import pino from "pino";

async function main() {
  const transport = pino.transport({
    target: "pino-pretty",
    options: {
      colorize: true,
      translateTime: "HH:MM:ss",
    },
  });

  const source = solanaPortalStream({
    id: "custom-logging",
    portal: "https://portal.sqd.dev/datasets/solana-mainnet",
    outputs: solanaQuery()
      .addFields({ block: { number: true, timestamp: true } })
      .includeAllBlocks()
      .build(),
    logger: pino(transport),
  });

  await source.pipeTo(
    createTarget({
      write: async ({ logger, read }) => {
        for await (const { data } of read()) {
          logger.info({ count: data.length }, "Processed batch");
        }
      },
    }),
  );
}

void main()
```

## Cloud transports

Only the `transport` changes per destination — the rest of the pipe above stays the same. Build the transport, then pass `pino(transport)` as the source `logger`.

<Tabs>
  <Tab title="GCP Cloud Logging">
    ```ts theme={"system"}
    const transport = pino.transport({
      target: "@google-cloud/logging-pino",
      options: {
        projectId: "your-project-id",
        logName: "pipes-indexer",
      },
    });
    ```
  </Tab>

  <Tab title="Sentry">
    Route only errors to Sentry, and wrap the write loop so failures surface as `logger.error`:

    ```ts theme={"system"}
    const transport = pino.transport({
      target: "pino-sentry-transport",
      options: {
        sentry: { dsn: process.env.SENTRY_DSN, environment: "production" },
        level: "error", // only forward errors to Sentry
      },
    });
    ```
  </Tab>

  <Tab title="Multiple transports">
    Fan out to several destinations at once, each with its own level:

    ```ts theme={"system"}
    const transport = pino.transport({
      targets: [
        { target: "pino-pretty", options: { colorize: true }, level: "info" },
        { target: "@google-cloud/logging-pino", options: { projectId: "your-project-id" }, level: "info" },
        { target: "pino-sentry-transport", options: { sentry: { dsn: process.env.SENTRY_DSN } }, level: "error" },
      ],
    });
    ```
  </Tab>
</Tabs>

<Tip>
  The `ctx.logger` in transformers and targets is the same logger instance passed to the source. Configure logging once at the source, then use `ctx.logger` throughout your pipeline.
</Tip>


## Related topics

- [Logging](/en/sdk/pipes-sdk/evm/guides/advanced-topics/logging.md)
- [Custom Resolvers](/en/sdk/squid-sdk/solana/reference/openreader/configuration/custom-resolvers.md)
- [Squid SDK tips and troubleshooting](/en/sdk/squid-sdk/tron/guides/advanced/tips-and-troubleshooting.md)
