Skip to content

Conversation

@fracek
Copy link
Contributor

@fracek fracek commented Nov 29, 2024

Add a new logger plugin to standardize how users can log information.
This is a simple wrapper around consola for now and will be used later
to make the logger configurable by the user in apibara.config.ts.

@coderabbitai
Copy link

coderabbitai bot commented Nov 29, 2024

📝 Walkthrough

Walkthrough

This pull request introduces several changes across multiple files, primarily focusing on the addition of a new logger plugin for the @apibara/indexer and apibara packages. New JSON files are created to specify prerelease versions and metadata for these packages. Modifications in indexer configurations include updates to logging functionality, such as the logging of endCursor and the removal of certain hooks. Additionally, the build configuration and package exports are updated to include the new logger plugin, enhancing the overall logging capabilities of the indexers.

Changes

File Path Change Summary
change/@apibara-indexer-95c6848e-72aa-429f-bbe9-556a867c123e.json New JSON file added for @apibara/indexer with prerelease details and logger plugin metadata.
change/apibara-45ec1e62-bbea-48bc-ac29-b6ea1acc4024.json New JSON configuration added for apibara with prerelease details and logger plugin metadata.
examples/cli/indexers/1-evm.indexer.ts Updated streamUrl to a remote endpoint; added startingCursor and transactions properties; modified transform method to log only endCursor; removed hooks object.
examples/cli/indexers/2-starknet.indexer.ts Added import for useLogger; updated transform method to log endCursor.
packages/cli/src/runtime/internal/app.ts Modified createIndexer to include logger plugin in the indexer definition.
packages/indexer/build.config.ts Added entry for ./src/plugins/logger.ts in build configuration.
packages/indexer/package.json Added export for ./plugins/logger with properties for TypeScript definitions and module resolution.
packages/indexer/src/plugins/logger.ts Introduced logger plugin with logging functionality; exported types and methods for integration.

Possibly related PRs

Suggested reviewers

  • jaipaljadeja

Poem

🐇 In the meadow where loggers play,
New plugins hop along the way.
With cursors logged and hooks set free,
The indexers dance in harmony.
A patch of joy, a patch of cheer,
Hooray for changes, the bunnies cheer! 🎉


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Outside diff range and nitpick comments (9)
examples/cli/indexers/1-evm.indexer.ts (1)

7-9: Document the significance of the starting block number

The 10_000_000n value appears to be a magic number. Consider adding a comment explaining why this specific block number was chosen as the starting point.

 startingCursor: {
+    // Start indexing from block 10M (post-merge block)
     orderKey: 10_000_000n,
 },
packages/indexer/src/plugins/logger.ts (2)

23-30: Improve error handling and add documentation

The useLogger hook could benefit from better documentation and type safety.

Consider these improvements:

+/**
+ * Hook to access the logger instance from the indexer context.
+ * @throws {Error} If logger plugin is not initialized in the indexer
+ * @returns Consola logger instance
+ */
 export function useLogger(): ConsolaInstance {
   const ctx = useIndexerContext();
 
-  if (!ctx?.logger)
-    throw new Error("Logger plugin is not available in context");
+  if (!ctx?.logger) {
+    throw new Error(
+      "Logger plugin is not available in context. Did you forget to add the logger plugin to your indexer?"
+    );
+  }
+
+  if (!('log' in ctx.logger)) {
+    throw new Error("Invalid logger instance in context");
+  }
 
   return ctx.logger;
 }

1-30: Consider future configuration requirements

Given the PR objective to support logger configuration through apibara.config.ts, consider these architectural improvements:

  1. Add a configuration interface that can be extended later:
export interface LoggerConfig {
  reporter?: ConsolaReporter;
  level?: string;
  // Future config options
  customFormats?: unknown;
  destination?: unknown;
}
  1. Modify the logger plugin to accept this configuration:
export function logger<T, B, P>(config: LoggerConfig = {})

This will make it easier to add new configuration options without breaking changes.

packages/cli/src/runtime/internal/app.ts (3)

37-40: Consider adding type annotations for better type safety

The logic for handling different indexer types is sound, but could benefit from explicit type annotations.

Consider adding type annotations:

-  const definition =
+  const definition: IndexerDefinition =
     typeof indexerDefinition.indexer === "function"
       ? indexerDefinition.indexer(runtimeConfig)
       : indexerDefinition.indexer;

42-42: Consider enhancing plugin management robustness

While the current implementation works, consider these improvements:

  1. Validate for duplicate plugins
  2. Consider making plugin addition immutable

Here's a more robust approach:

-  definition.plugins = [...(definition.plugins ?? []), logger()];
+  const existingPlugins = definition.plugins ?? [];
+  const newDefinition = {
+    ...definition,
+    plugins: existingPlugins.some(p => p.name === 'logger') 
+      ? existingPlugins 
+      : [...existingPlugins, logger()]
+  };

37-44: Consider configuration flexibility for logger plugin

The current implementation adds the logger plugin globally to all indexers. As mentioned in the PR objectives, future configuration will be handled via apibara.config.ts. Consider:

  1. Adding a mechanism to disable the logger for specific indexers
  2. Allowing logger configuration options to be passed through runtimeConfig
  3. Supporting different log levels per indexer

This will provide better flexibility when the configuration feature is implemented:

// Future apibara.config.ts example
export default {
  logger: {
    enabled: true,
    level: 'info',
    // per-indexer settings
    indexers: {
      'my-indexer': {
        level: 'debug'
      }
    }
  }
}
examples/cli/indexers/2-starknet.indexer.ts (2)

35-37: Enhance logging information for better debugging

While the basic logging is in place, consider including more context about the block being transformed, such as the block number and hash.

- logger.info("Transforming block ", endCursor);
+ logger.info("Transforming block", { 
+   cursor: endCursor,
+   blockNumber: header?.blockNumber.toString(),
+   blockHash: header?.blockHash 
+ });

Remove commented block data insertion code

The commented code is part of an example indexer implementation and appears to be unused. The code block is meant to demonstrate block data insertion but is currently inactive and should be removed since:

  • The table 'test' is created with columns matching these fields (number, hash)
  • No alternative block data insertion logic is implemented
  • This is an example file (in examples/cli/indexers/) meant to demonstrate indexer functionality
  • Keeping commented code reduces readability and may confuse users following the example
🔗 Analysis chain

Line range hint 39-42: Remove or implement commented code

There's commented-out code that appears to be the actual block data insertion logic. This should either be implemented or removed if no longer needed.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if this insertion pattern is used elsewhere in the codebase
ast-grep --pattern 'writer.insert([{
  number: $$$,
  hash: $$$
}])'

Length of output: 70


Script:

#!/bin/bash
# Let's try a broader search for writer.insert patterns and commented code around it
rg -U "writer\.insert.*?number.*?hash" -A 5 -B 5

Length of output: 50


Script:

#!/bin/bash
# Search for similar commented block data insertion patterns
rg -U "//.*writer\.insert.*?number.*?hash" -A 5 -B 5

Length of output: 54


Script:

#!/bin/bash
# Let's also check the specific file for context
cat "examples/cli/indexers/2-starknet.indexer.ts"

Length of output: 1614

packages/indexer/package.json (1)

Line range hint 2-2: Consider version bump for new plugin addition.

Adding a new plugin is a feature addition. Since the current version is 2.0.0-beta.19, consider bumping the version according to semver guidelines.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between a177c8d and c402e05.

📒 Files selected for processing (8)
  • change/@apibara-indexer-95c6848e-72aa-429f-bbe9-556a867c123e.json (1 hunks)
  • change/apibara-45ec1e62-bbea-48bc-ac29-b6ea1acc4024.json (1 hunks)
  • examples/cli/indexers/1-evm.indexer.ts (1 hunks)
  • examples/cli/indexers/2-starknet.indexer.ts (2 hunks)
  • packages/cli/src/runtime/internal/app.ts (2 hunks)
  • packages/indexer/build.config.ts (1 hunks)
  • packages/indexer/package.json (1 hunks)
  • packages/indexer/src/plugins/logger.ts (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • change/@apibara-indexer-95c6848e-72aa-429f-bbe9-556a867c123e.json
  • change/apibara-45ec1e62-bbea-48bc-ac29-b6ea1acc4024.json
🔇 Additional comments (10)
examples/cli/indexers/1-evm.indexer.ts (2)

5-5: Consider using a more stable URL for examples

The preview environment URL might not be the best choice for example code as it could be subject to changes. Consider using a placeholder URL or adding a comment explaining this is for demonstration purposes only.


11-13: Review the transaction filter configuration

The empty transaction filter [{}] will match all transactions, which might not be optimal for performance. Consider:

  1. Adding comments to explain why all transactions are being captured
  2. Adding specific filters if only certain transactions are needed
✅ Verification successful

Let me gather more context about the usage and purpose of these filters by checking the surrounding code and documentation.


Let me check if there are any comments or documentation about the filter usage in the codebase.


Based on the context gathered, I can now provide the final response:

Empty transaction filter is intentional in example code

The empty transaction filter [{}] is a valid pattern used consistently across example code to capture all transactions when demonstrating basic indexer functionality. This is evidenced by:

  • Similar usage in examples/evm-client/src/main.ts for demonstration purposes
  • Other example indexers showing how to add specific filters when needed (e.g., examples/indexer/src/indexer.ts with strict and topics)

The current implementation serves as a basic example and is appropriate in this context.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if this pattern is used consistently in other example indexers
rg -A 2 "transactions: \[\{\}\]" examples/

Length of output: 393


Script:

#!/bin/bash
# Check the full context of both files to understand the purpose
echo "=== examples/cli/indexers/1-evm.indexer.ts ==="
cat examples/cli/indexers/1-evm.indexer.ts

echo -e "\n=== examples/evm-client/src/main.ts ==="
cat examples/evm-client/src/main.ts

# Check if there are any comments or documentation about filters
echo -e "\n=== Searching for filter documentation ==="
rg -i "filter" examples/ -A 5 -B 5

Length of output: 139383


Script:

#!/bin/bash
# Search for any documentation about filters in markdown files or comments
echo "=== Searching for filter documentation in markdown files ==="
fd -e md | xargs rg -i "filter|transaction" -A 5 -B 5

echo -e "\n=== Searching for filter documentation in comments ==="
rg -g "!*.json" "filter|transaction" -A 5 -B 5 examples/

Length of output: 16439

packages/indexer/build.config.ts (2)

13-13: LGTM! The logger plugin entry is properly integrated.

The new entry for the logger plugin follows the established pattern and is correctly placed in the plugins section of the build configuration.


13-13: Verify the logger plugin implementation and exports.

Let's ensure the logger plugin file exists and is properly exported.

✅ Verification successful

Let me verify the logger plugin implementation with one more check to ensure it's properly implemented.


Logger plugin implementation and exports are properly configured

The verification shows that:

  • The logger plugin file exists at the correct location
  • It's properly exported in package.json with all necessary formats (CJS, MJS, and types)
  • The implementation is complete with:
    • A plugin factory function that configures the logger
    • A useLogger hook for accessing the logger instance
    • Proper type exports from 'consola'
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the existence of the logger plugin file and its exports

# Check if the logger plugin file exists
echo "Checking for logger plugin file..."
fd "logger.ts" "packages/indexer/src/plugins"

# Check if the logger is properly exported in package.json
echo "Checking package exports..."
cat packages/indexer/package.json | jq '.exports["./plugins/logger"]'

# Look for logger plugin imports to ensure it's being used
echo "Checking logger plugin usage..."
rg -t ts "useLogger|from.*plugins/logger" "packages/indexer"

Length of output: 687


Script:

#!/bin/bash
# Check the implementation of the logger plugin
echo "Checking logger plugin implementation..."
cat packages/indexer/src/plugins/logger.ts

Length of output: 995

packages/indexer/src/plugins/logger.ts (1)

1-5: LGTM! Clean imports and type exports

The imports are well-organized and the type re-exports provide good TypeScript support for plugin consumers.

packages/cli/src/runtime/internal/app.ts (2)

2-2: LGTM: Logger import is properly structured

The import statement follows the project's module organization pattern, correctly importing from the plugins directory.


44-44: Verify error handling in _createIndexer

Ensure that _createIndexer properly handles potential errors from plugin initialization.

examples/cli/indexers/2-starknet.indexer.ts (2)

2-2: LGTM: Logger import is properly structured

The import statement follows the plugin architecture pattern and is correctly placed with other imports.


Line range hint 35-43: Verify error handling for endCursor

The transform function now accepts endCursor but there's no error handling if it's undefined. Consider adding validation or type checking.

packages/indexer/package.json (1)

55-60: LGTM! Verify dist files existence.

The export configuration for the logger plugin follows the established pattern and correctly defines all necessary module formats.

Let's verify the existence of the referenced dist files:

✅ Verification successful

Export configuration is correct and will be built properly

The logger plugin export configuration is valid and consistent with other plugins. The source file src/plugins/logger.ts exists and is properly included in the build configuration via unbuild. The build system will generate the necessary files in the dist directory with the correct formats (mjs, cjs, d.ts) matching the export paths.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that all referenced logger plugin files exist in the dist directory
fd --glob "dist/plugins/logger.{d.ts,mjs,cjs}" --type f

Length of output: 57


Script:

#!/bin/bash
# Let's check if the source files exist first
fd --glob "src/plugins/logger.{ts,js}" --type f

# Also check the build script to understand the dist structure
cat package.json | jq '.scripts.build'

# Check if there are any other plugins to compare the structure
fd --glob "src/plugins/*.{ts,js}" --type f

Length of output: 151


Script:

#!/bin/bash
# Let's check the entire src directory structure to understand the plugin organization
fd --type f --extension ts --extension js

# Let's also check if there are any build configuration files
fd --glob "{tsconfig.json,rollup.config.*,vite.config.*}" --type f

Length of output: 6263


Script:

#!/bin/bash
# Let's check the build configuration for the indexer package
cat packages/indexer/build.config.ts

# And check if there are any other plugin exports in package.json
cat packages/indexer/package.json | jq '.exports'

Length of output: 2484

Comment on lines +14 to 16
async transform({ endCursor }) {
console.log({ endCursor });
},
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 });
},

Comment on lines +7 to +21
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({});
}
});
});
}
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();
}
});
});
}

Copy link
Member

@jaipaljadeja jaipaljadeja left a comment

Choose a reason for hiding this comment

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

This is good! Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants