> ## 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.

<AgentInstructions>

## Submitting Feedback

If you encounter incorrect, outdated, or confusing documentation on this page, submit feedback:

POST https://docs.sqd.dev/feedback

```json
{
  "path": "/en/sdk/pipes-sdk/solana/guides/advanced-topics/logging",
  "feedback": "Description of the issue"
}
```

Only submit feedback when you have something specific and actionable to report.

</AgentInstructions>

# Logging

> Customize logging with Pino-compatible transports

[solanaPortalSource()](../../reference/basic-components/source) accepts a Pino-compatible `logger`, allowing you to integrate custom log transports and send logs to external services like GCP Cloud Logging, Sentry, or any other Pino-compatible destination.

## Basic custom logger

Pass a custom logger to the source to configure logging for your entire pipeline.

```ts theme={"system"}
import { createTarget } from "@subsquid/pipes";
import { solanaPortalSource } 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 = solanaPortalSource({
    portal: "https://portal.sqd.dev/datasets/solana-mainnet",
    logger: pino(transport),
  });

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

  await source.pipeTo(target);
}

void main()
```

## Integration with cloud services

You can use any Pino transport to send logs to cloud services. Pass the configured logger to the source.

<Tabs>
  <Tab title="GCP Cloud Logging">
    ```ts theme={"system"}
    import { createTarget } from "@subsquid/pipes";
    import { solanaPortalSource } from "@subsquid/pipes/solana";
    import pino from "pino";

    async function main() {
      const transport = pino.transport({
        target: "@google-cloud/logging-pino",
        options: {
          projectId: "your-project-id",
          logName: "pipes-indexer",
        },
      });

      const source = solanaPortalSource({
        portal: "https://portal.sqd.dev/datasets/solana-mainnet",
        logger: pino(transport),
      });

      const target = createTarget({
        write: async ({ logger, read }) => {
          for await (const { data } of read()) {
            logger.info(
              {
                blocksProcessed: data.blocks?.length,
                eventsCount: data.transfer?.length,
              },
              "Batch processed"
            );
          }
        },
      });

      await source.pipeTo(target);
    }

    void main()
    ```
  </Tab>

  <Tab title="Sentry">
    ```ts theme={"system"}
    import { createTarget } from "@subsquid/pipes";
    import { solanaPortalSource } from "@subsquid/pipes/solana";
    import pino from "pino";

    async function main() {
      const transport = pino.transport({
        target: "pino-sentry-transport",
        options: {
          sentry: {
            dsn: process.env.SENTRY_DSN,
            environment: "production",
          },
          level: "error", // Only send errors to Sentry
        },
      });

      const source = solanaPortalSource({
        portal: "https://portal.sqd.dev/datasets/solana-mainnet",
        logger: pino(transport),
      });

      const target = createTarget({
        write: async ({ logger, read }) => {
          for await (const { data } of read()) {
            try {
              await processData(data);
              logger.info({ count: data.length }, "Batch processed");
            } catch (error) {
              logger.error({ error, data }, "Failed to process batch");
            }
          }
        },
      });

      await source.pipeTo(target);
    }

    void main()
    ```
  </Tab>

  <Tab title="Multiple Transports">
    ```ts theme={"system"}
    import { createTarget } from "@subsquid/pipes";
    import { solanaPortalSource } from "@subsquid/pipes/solana";
    import pino from "pino";

    async function main() {
      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",
          },
        ],
      });

      const source = solanaPortalSource({
        portal: "https://portal.sqd.dev/datasets/solana-mainnet",
        logger: pino(transport),
      });

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

      await source.pipeTo(target);
    }

    void main()
    ```
  </Tab>
</Tabs>

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