Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "Add logger plugin",
"packageName": "@apibara/indexer",
"email": "francesco@ceccon.me",
"dependentChangeType": "patch"
}
7 changes: 7 additions & 0 deletions change/apibara-45ec1e62-bbea-48bc-ac29-b6ea1acc4024.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "Add logger plugin",
"packageName": "apibara",
"email": "francesco@ceccon.me",
"dependentChangeType": "patch"
}
15 changes: 7 additions & 8 deletions examples/cli/indexers/1-evm.indexer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,16 @@ import { EvmStream } from "@apibara/evm";
import { defineIndexer } from "@apibara/indexer";

export default defineIndexer(EvmStream)({
streamUrl: "http://localhost:7007",
streamUrl: "https://ethereum.preview.apibara.org",
finality: "accepted",
startingCursor: {
orderKey: 10_000_000n,
},
filter: {
header: "always",
transactions: [{}],
},
async transform({ cursor, endCursor }) {
console.log({ cursor, endCursor });
},
hooks: {
"message:invalidate"({ message }) {
console.warn(message);
},
async transform({ endCursor }) {
console.log({ endCursor });
},
Comment on lines +14 to 16
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Use the new logger plugin instead of console.log

Since this PR introduces a logger plugin for standardizing logging, this example should demonstrate its usage instead of using console.log directly.

-async transform({ endCursor }) {
-  console.log({ endCursor });
+async transform({ endCursor }, { logger }) {
+  logger.info('Processing block', { endCursor });
 },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async transform({ endCursor }) {
console.log({ endCursor });
},
async transform({ endCursor }, { logger }) {
logger.info('Processing block', { endCursor });
},

});
5 changes: 4 additions & 1 deletion examples/cli/indexers/2-starknet.indexer.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { defineIndexer, useSink } from "@apibara/indexer";
import { useLogger } from "@apibara/indexer/plugins/logger";
import { sqlite } from "@apibara/indexer/sinks/sqlite";
import { StarknetStream } from "@apibara/starknet";
import type { ApibaraRuntimeConfig } from "apibara/types";
Expand Down Expand Up @@ -31,7 +32,9 @@ export default function (runtimeConfig: ApibaraRuntimeConfig) {
},
],
},
async transform({ block: { header }, context }) {
async transform({ endCursor, block: { header }, context }) {
const logger = useLogger();
logger.info("Transforming block ", endCursor);
const { writer } = useSink({ context });

// writer.insert([{
Expand Down
12 changes: 9 additions & 3 deletions packages/cli/src/runtime/internal/app.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { createIndexer as _createIndexer } from "@apibara/indexer";
import { logger } from "@apibara/indexer/plugins/logger";

import { config } from "#apibara-internal-virtual/config";
import { indexers } from "#apibara-internal-virtual/indexers";
Expand Down Expand Up @@ -33,7 +34,12 @@ export function createIndexer(indexerName: string, preset?: string) {
);
}

return typeof indexerDefinition.indexer === "function"
? _createIndexer(indexerDefinition.indexer(runtimeConfig))
: _createIndexer(indexerDefinition.indexer);
const definition =
typeof indexerDefinition.indexer === "function"
? indexerDefinition.indexer(runtimeConfig)
: indexerDefinition.indexer;

definition.plugins = [...(definition.plugins ?? []), logger()];

return _createIndexer(definition);
}
1 change: 1 addition & 0 deletions packages/indexer/build.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export default defineBuildConfig({
"./src/vcr/index.ts",
"./src/plugins/index.ts",
"./src/plugins/kv.ts",
"./src/plugins/logger.ts",
"./src/plugins/persistence.ts",
],
clean: true,
Expand Down
6 changes: 6 additions & 0 deletions packages/indexer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@
"require": "./dist/plugins/index.cjs",
"default": "./dist/plugins/index.mjs"
},
"./plugins/logger": {
"types": "./dist/plugins/logger.d.ts",
"import": "./dist/plugins/logger.mjs",
"require": "./dist/plugins/logger.cjs",
"default": "./dist/plugins/logger.mjs"
},
"./plugins/kv": {
"types": "./dist/plugins/kv.d.ts",
"import": "./dist/plugins/kv.mjs",
Expand Down
30 changes: 30 additions & 0 deletions packages/indexer/src/plugins/logger.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { type ConsolaInstance, type ConsolaReporter, consola } from "consola";
import { useIndexerContext } from "../context";
import { defineIndexerPlugin } from "./config";

export type { ConsolaReporter, ConsolaInstance } from "consola";

export function logger<TFilter, TBlock, TTxnParams>({
logger,
}: { logger?: ConsolaReporter } = {}) {
return defineIndexerPlugin<TFilter, TBlock, TTxnParams>((indexer) => {
indexer.hooks.hook("run:before", () => {
const ctx = useIndexerContext();

if (logger) {
ctx.logger = consola.create({ reporters: [logger] });
} else {
ctx.logger = consola.create({});
}
});
});
}
Comment on lines +7 to +21
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add cleanup, error handling, and type constraints

The logger plugin implementation could be improved in several areas:

  1. Add cleanup in "run:after" hook to prevent memory leaks
  2. Add error handling for logger creation
  3. Add type constraints for better type safety
  4. Add JSDoc documentation

Consider this implementation:

+/**
+ * Creates a logger plugin for the indexer.
+ * @param options - Plugin options
+ * @param options.logger - Optional custom consola reporter
+ * @returns Indexer plugin that provides logging capabilities
+ */
-export function logger<TFilter, TBlock, TTxnParams>({
+export function logger<
+  TFilter extends Record<string, unknown>,
+  TBlock extends Record<string, unknown>,
+  TTxnParams extends Record<string, unknown>
+>({
   logger,
 }: { logger?: ConsolaReporter } = {}) {
   return defineIndexerPlugin<TFilter, TBlock, TTxnParams>((indexer) => {
     indexer.hooks.hook("run:before", () => {
       const ctx = useIndexerContext();
 
+      try {
         if (logger) {
           ctx.logger = consola.create({ reporters: [logger] });
         } else {
           ctx.logger = consola.create({});
         }
+      } catch (error) {
+        throw new Error(`Failed to initialize logger: ${error.message}`);
+      }
     });
+
+    indexer.hooks.hook("run:after", () => {
+      const ctx = useIndexerContext();
+      if (ctx.logger) {
+        // Clear any internal buffers or state
+        ctx.logger.clear();
+      }
+    });
   });
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export function logger<TFilter, TBlock, TTxnParams>({
logger,
}: { logger?: ConsolaReporter } = {}) {
return defineIndexerPlugin<TFilter, TBlock, TTxnParams>((indexer) => {
indexer.hooks.hook("run:before", () => {
const ctx = useIndexerContext();
if (logger) {
ctx.logger = consola.create({ reporters: [logger] });
} else {
ctx.logger = consola.create({});
}
});
});
}
/**
* Creates a logger plugin for the indexer.
* @param options - Plugin options
* @param options.logger - Optional custom consola reporter
* @returns Indexer plugin that provides logging capabilities
*/
export function logger<
TFilter extends Record<string, unknown>,
TBlock extends Record<string, unknown>,
TTxnParams extends Record<string, unknown>
>({
logger,
}: { logger?: ConsolaReporter } = {}) {
return defineIndexerPlugin<TFilter, TBlock, TTxnParams>((indexer) => {
indexer.hooks.hook("run:before", () => {
const ctx = useIndexerContext();
try {
if (logger) {
ctx.logger = consola.create({ reporters: [logger] });
} else {
ctx.logger = consola.create({});
}
} catch (error) {
throw new Error(`Failed to initialize logger: ${error.message}`);
}
});
indexer.hooks.hook("run:after", () => {
const ctx = useIndexerContext();
if (ctx.logger) {
// Clear any internal buffers or state
ctx.logger.clear();
}
});
});
}


export function useLogger(): ConsolaInstance {
const ctx = useIndexerContext();

if (!ctx?.logger)
throw new Error("Logger plugin is not available in context");

return ctx.logger;
}