Codumentor logo Codumentor

Log Collection Plugin

The Log Collection Plugin enables Codumentor to analyze and interact with log files. It provides a complete source type with a full-featured UI for managing collections of log files and starting conversations scoped to them.

This plugin also serves as the reference implementation for developers building custom source-type plugins (e.g., database schema analyzer, S3 bucket browser, API endpoint explorer). See Building a Source-Type Plugin below.

Architecture

The plugin extends Codumentor's source types through three mechanisms:

  1. Source Provider Registration — Registers a custom source provider via the onRegisterSourceProviders hook
  2. Dynamic Tool Registration — Provides tool factories for runtime tool registration per session
  3. UI Integration — Delivers custom UI components through the plugin manifest
src/codumentor/plugins/log_collection/
├── __init__.py
├── plugin.py                      # Main plugin class
└── sources/
    ├── provider.py               # LogCollectionSourceProvider
    ├── routes.py                 # FastAPI CRUD routes
    ├── store.py                  # SQLite storage
    ├── tools.py                  # Agent tools
    └── workspace.py              # Symlink workspace manager

ui/plugins/log_collection/
└── src/components/
    ├── collections-widget.ts     # Welcome page widget
    ├── collection-form-page.ts   # Create/edit form
    └── collection-banner.ts      # Conversation header banner

Configuration

plugins:
  - module: codumentor.plugins.log_collection
    class: LogCollectionPlugin
    priority: 50
    args:
      enabled: true

Building the UI Bundle

cd ui/plugins/log_collection
npm install
npm run build

The built bundle is served automatically at /ui/extensions/plugins/log_collection/index.js.

Usage

Creating a Log Collection

Via UI:

  1. Navigate to the welcome page
  2. Click + New Collection in the Log Collections widget
  3. Fill in the collection details: - Name: Collection identifier - Description: Optional description - Isolation Mode: isolated (log files only) or merged (log files + code repos)
  4. Add files with Label, Real Path, and Symlink Name
  5. Click Create Collection

Via API:

curl -X POST http://localhost:2638/ui/plugins/log_collection \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"name": "production-logs", "description": "Prod logs", "isolation_mode": "isolated"}'

Starting a Conversation with a Log Collection

Via UI: Click Analyze on a collection in the widget.

Via API:

curl -X POST "http://localhost:2638/ui/conversations?source_type=log_collection&source_id=1" \
  -H "Authorization: Bearer $TOKEN"

API Reference

All endpoints are mounted under /ui/plugins/log_collection/:

MethodPathDescription
GET/summaryCollection summaries with file counts (for UI widget)
POST/Create a new collection
GET/List all collections for the authenticated user
GET/{id}Get collection details with files
PUT/{id}Update collection metadata
DELETE/{id}Delete a collection
POST/{id}/filesAdd files to a collection
DELETE/{id}/files/{file_id}Remove a file from a collection

Adding Files

curl -X POST http://localhost:2638/ui/plugins/log_collection/1/files \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{
    "files": [{"label": "App Log", "real_path": "/var/log/app.log", "symlink_name": "app.log"}]
  }'

UI Components

ComponentElementPlacementDescription
Collections Widgetx-log-collections-widgetWelcome pageList collections; start, edit, delete; auto-refreshes every 30s
Collection Formx-log-collection-form-page/plugins/log_collection/create and edit/:idCreate/edit form with dynamic file list
Collection Bannerx-log-collection-bannerMessage list headerShows active collection name, description, file count

Agent Tools

The plugin provides two tools for runtime collection management during a conversation:

manage_log_collection

Create, list, get, update, or delete collections.

{"action": "create", "name": "debug-logs", "isolation_mode": "isolated"}

manage_log_collection_files

Add, list, or remove files within a collection.

{"action": "add", "collection_id": 1, "files": [{"label": "Error Log", "real_path": "/var/log/error.log", "symlink_name": "error.log"}]}

Isolation Modes

ModeDescriptionDisabled Tools
isolatedOnly log files are visible; no code reposknowledge_search, replace_in_file, write_file, agentic_developer
mergedLog files + all code repos; all tools enabled

Troubleshooting

Collections widget doesn't appear: Check plugin config, verify enabled: true, check server logs for "LogCollectionPlugin registered", rebuild UI bundle.

404 on collection API: Verify the collection belongs to the authenticated user and the ID is correct.

Agent can't read log files: Verify real_path exists and is readable, check that paths are absolute, verify file permissions.


Building a Source-Type Plugin

This plugin is the canonical reference for creating custom source types. The pattern has four parts:

1. Register a Source Provider

async def _on_register_source_providers(self, agent, ctx, payload):
    providers = dict(payload.get("providers", {}))
    providers["my_source"] = lambda cfg: MySourceProvider(cfg)
    return {"type": "continue", "patch": {"providers": providers}}

2. Implement SourceProvider

from codumentor.sources.protocol import SourceContext, SourceProvider

class MySourceProvider(SourceProvider):
    def prepare(self, session_id: str, **kwargs) -> SourceContext:
        working_dir = Path("/tmp/workspaces") / session_id
        working_dir.mkdir(parents=True, exist_ok=True)

        return SourceContext(
            source_type="my_source",
            working_dir=working_dir,
            repo_paths={"my_source": str(working_dir)},
            tool_factories=[
                lambda cfg, cb: MySourceTool(cfg, input_callback=cb),
            ],
            cleanup=lambda: shutil.rmtree(working_dir, ignore_errors=True),
        )

3. Create UI Components

import { BasePluginElement } from "@codumentor/plugin-sdk";

class MySourceWidget extends BasePluginElement {
  connectedCallback() {
    this._shadowRoot.innerHTML = `<div>My Source Widget</div>`;
  }
}
customElements.define("x-my-source-widget", MySourceWidget);

4. Declare the UI Manifest

def ui_manifest(self):
    return {
        "plugin_id": "my_source",
        "name": "My Source",
        "version": "1.0.0",
        "ui": {
            "bundle_url": "/ui/extensions/plugins/my_source/index.js",
            "sdk_version": "1.0.0",
            "custom_elements": ["x-my-source-widget"],
            "placements": ["welcome"],
            "widgets": [{"widget_id": "list", "title": "My Sources", "placement": "welcome", "priority": 20, "custom_element": "x-my-source-widget"}],
        },
    }

See the full implementation at src/codumentor/plugins/log_collection/ and ui/plugins/log_collection/.

See Also