PlansShared Logging Package

Shared logging package not working Implementation Plan

For Claude: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.

Goal: errors deploying backend and cloud function as there is something not quite right with the shared logging

Architecture: See task descriptions below.

Tech Stack: See implementation details.


Task 1: Add missing logger API methods to glogger package

Files:

  • Test: shared/python/tests/test_logger_api.py
  • Modify: shared/python/glogger/factory.py:71-94

Step 1: Create test file for new logger API methods

"""Tests for logger API compatibility methods."""
import pytest
from glogger.factory import DefaultLogger
from glogger.providers.console import ConsoleProvider
from glogger.interfaces import LogLevel
 
 
class MockProvider:
    """Mock provider for testing."""
    def __init__(self):
        self.logged_entries = []
    
    def log(self, entry):
        self.logged_entries.append(entry)
    
    def close(self):
        pass
 
 
class TestLoggerCompatibilityAPI:
    """Test the *_with_context methods for backward compatibility."""
    
    def test_info_with_context(self):
        """Test info_with_context method."""
        provider = MockProvider()
        logger = DefaultLogger("test", provider, {})
        
        logger.info_with_context("Test message", {"key": "value", "request_id": "123"})
        
        assert len(provider.logged_entries) == 1
        entry = provider.logged_entries[0]
        assert entry.message == "Test message"
        assert entry.level == LogLevel.INFO
        assert entry.context.custom["key"] == "value"
        assert entry.context.custom["request_id"] == "123"
    
    def test_error_with_context(self):
        """Test error_with_context method."""
        provider = MockProvider()
        logger = DefaultLogger("test", provider, {})
        
        logger.error_with_context("Error occurred", {"status_code": 500, "path": "/api/test"})
        
        assert len(provider.logged_entries) == 1
        entry = provider.logged_entries[0]
        assert entry.message == "Error occurred"
        assert entry.level == LogLevel.ERROR
        assert entry.context.custom["status_code"] == 500
        assert entry.context.custom["path"] == "/api/test"
    
    def test_exception_with_context(self):
        """Test exception_with_context method."""
        provider = MockProvider()
        logger = DefaultLogger("test", provider, {})
        
        test_exception = ValueError("Test error")
        logger.exception_with_context(
            "Exception occurred",
            {"error_type": "ValueError", "request_id": "456"}
        )
        
        assert len(provider.logged_entries) == 1
        entry = provider.logged_entries[0]
        assert entry.message == "Exception occurred"
        assert entry.level == LogLevel.ERROR
        assert entry.context.custom["error_type"] == "ValueError"
        assert entry.context.custom["request_id"] == "456"
    
    def test_info_with_context_empty_dict(self):
        """Test info_with_context with empty context dict."""
        provider = MockProvider()
        logger = DefaultLogger("test", provider, {})
        
        logger.info_with_context("Message", {})
        
        assert len(provider.logged_entries) == 1
        assert provider.logged_entries[0].message == "Message"
    
    def test_error_with_context_merges_default_context(self):
        """Test that *_with_context methods merge with default context."""
        provider = MockProvider()
        logger = DefaultLogger("test", provider, {"default_key": "default_value"})
        
        logger.error_with_context("Error", {"error_key": "error_value"})
        
        entry = provider.logged_entries[0]
        assert entry.context.custom["default_key"] == "default_value"
        assert entry.context.custom["error_key"] == "error_value"

Expected: Test file created at shared/python/tests/test_logger_api.py

Step 2: Run tests to verify they fail

Run: cd /Users/nicholas/Documents/code/turbulence && source ~/Documents/venvs/turbulence/bin/activate && python -m pytest shared/python/tests/test_logger_api.py -v Expected: AttributeError: ‘DefaultLogger’ object has no attribute ‘info_with_context’ AttributeError: ‘DefaultLogger’ object has no attribute ‘error_with_context’ AttributeError: ‘DefaultLogger’ object has no attribute ‘exception_with_context’ FAILED (multiple test failures)

Step 3: Add compatibility methods to DefaultLogger class

    def info_with_context(self, message: str, context: Dict[str, Any]) -> None:
        """Log an info message with context dict (compatibility method)."""
        self.info(message, **context)
 
    def error_with_context(self, message: str, context: Dict[str, Any]) -> None:
        """Log an error message with context dict (compatibility method)."""
        self.error(message, **context)
 
    def exception_with_context(self, message: str, context: Dict[str, Any]) -> None:
        """Log an exception with context dict (compatibility method)."""
        self.error(message, **context)

Expected: Three new methods added to DefaultLogger after line 94 in factory.py

Step 4: Run tests to verify they pass

Run: cd /Users/nicholas/Documents/code/turbulence && source ~/Documents/venvs/turbulence/bin/activate && python -m pytest shared/python/tests/test_logger_api.py -v Expected: test_info_with_context PASSED test_error_with_context PASSED test_exception_with_context PASSED test_info_with_context_empty_dict PASSED test_error_with_context_merges_default_context PASSED 5 passed

Step 5: Commit the logger API changes

Run: `cd /Users/nicholas/Documents/code/turbulence && git add shared/python/glogger/factory.py shared/python/tests/test_logger_api.py && git commit -m ”$(cat <<‘EOF’ feat: add compatibility methods for logger API

Add info_with_context, error_with_context, and exception_with_context methods to DefaultLogger for backward compatibility with existing backend code that expects these method signatures.

🤖 Generated with Claude Code

Co-Authored-By: Claude Sonnet 4.5 noreply@anthropic.com EOF )”` Expected: [main abc1234] feat: add compatibility methods for logger API 2 files changed

Commit:

git add shared/python/tests/test_logger_api.py shared/python/glogger/factory.py
git commit -m "feat: add compatibility methods for logger API"

Task 2: Fix backend Dockerfile to include complete shared package

Files:

  • Test: backend/Dockerfile.test
  • Modify: backend/Dockerfile:5-7

Step 1: Create test Dockerfile to verify build

FROM python:3.13-slim
 
WORKDIR /app
 
# Test that we copy the complete shared package structure
COPY shared/python/ ./shared/python/
COPY backend/requirements.txt ./requirements.txt
 
# This should succeed if setup.py is present
RUN pip install --no-cache-dir -r requirements.txt
 
# Verify glogger can be imported
RUN python -c "from glogger import logger; print('glogger imported successfully')"
 
COPY backend/ ./
 
ENV PORT=8080
EXPOSE ${PORT}
CMD ["sh", "-c", "uvicorn app:app --host 0.0.0.0 --port ${PORT}"]

Expected: Test Dockerfile created at backend/Dockerfile.test

Step 2: Run test build to verify it fails with current structure

Run: cd /Users/nicholas/Documents/code/turbulence && docker build -f backend/Dockerfile.test -t backend-test . Expected: ERROR: Could not find a version that satisfies the requirement glogger ERROR: Directory ’./shared/python’ is not installable Build fails

Step 3: Update backend Dockerfile to copy complete shared package

# Change line 5 from:
# COPY shared/python/glogger/ ./shared/python/glogger/
# To:
COPY shared/python/ ./shared/python/

Expected: Line 5 in backend/Dockerfile modified to copy entire shared/python directory

Step 4: Run test build to verify it passes

Run: cd /Users/nicholas/Documents/code/turbulence && docker build -f backend/Dockerfile.test -t backend-test . && docker run --rm backend-test python -c "from glogger import logger; print('Success')" Expected: Successfully built backend-test Success Build succeeds and glogger imports correctly

Step 5: Clean up test Dockerfile

Run: cd /Users/nicholas/Documents/code/turbulence && rm backend/Dockerfile.test Expected: Test Dockerfile removed

Step 6: Commit the backend Dockerfile fix

Run: `cd /Users/nicholas/Documents/code/turbulence && git add backend/Dockerfile && git commit -m ”$(cat <<‘EOF’ fix: copy complete shared package in backend Dockerfile

Change COPY directive to include entire shared/python directory including setup.py, which is required for pip editable install.

Previously only copied glogger/ subdirectory, causing pip install to fail when trying to install -e ./shared/python.

🤖 Generated with Claude Code

Co-Authored-By: Claude Sonnet 4.5 noreply@anthropic.com EOF )”` Expected: [main def5678] fix: copy complete shared package in backend Dockerfile 1 file changed

Commit:

git add backend/Dockerfile.test backend/Dockerfile
git commit -m "fix: copy complete shared package in backend Dockerfile"

Task 3: Fix cloud function Dockerfile to include complete shared package

Files:

  • Test: cloud-functions/video-processor/Dockerfile.test
  • Modify: cloud-functions/video-processor/Dockerfile:16-18

Step 1: Create test Dockerfile for cloud function

FROM functions-framework-python:3.11
 
RUN apt-get update && \
    apt-get install -y \
        ffmpeg \
        curl \
    && rm -rf /var/lib/apt/lists/* \
    && apt-get clean
 
RUN ffmpeg -version && ffprobe -version
 
WORKDIR /workspace
 
# Test copying complete shared package
COPY shared/python/ ./shared/python/
COPY cloud-functions/video-processor/ ./
 
# This should succeed if setup.py is present
RUN pip install --no-cache-dir -r requirements.txt
 
# Verify glogger can be imported
RUN python -c "from glogger import get_component_logger; logger = get_component_logger('test'); print('glogger imported successfully')"

Expected: Test Dockerfile created at cloud-functions/video-processor/Dockerfile.test

Step 2: Run test build to verify it fails with current structure

Run: cd /Users/nicholas/Documents/code/turbulence && docker build -f cloud-functions/video-processor/Dockerfile.test -t video-processor-test . Expected: ERROR: Could not find a version that satisfies the requirement glogger ERROR: Directory ’./shared/python’ is not installable Build fails

Step 3: Update cloud function Dockerfile to copy complete shared package

# Change line 16 from:
# COPY shared/python/glogger/ ./shared/python/glogger/
# To:
COPY shared/python/ ./shared/python/

Expected: Line 16 in cloud-functions/video-processor/Dockerfile modified

Step 4: Run test build to verify it passes

Run: cd /Users/nicholas/Documents/code/turbulence && docker build -f cloud-functions/video-processor/Dockerfile.test -t video-processor-test . && docker run --rm video-processor-test python -c "from glogger import get_component_logger; print('Success')" Expected: Successfully built video-processor-test Success Build succeeds and glogger imports correctly

Step 5: Clean up test Dockerfile

Run: cd /Users/nicholas/Documents/code/turbulence && rm cloud-functions/video-processor/Dockerfile.test Expected: Test Dockerfile removed

Step 6: Commit the cloud function Dockerfile fix

Run: `cd /Users/nicholas/Documents/code/turbulence && git add cloud-functions/video-processor/Dockerfile && git commit -m ”$(cat <<‘EOF’ fix: copy complete shared package in video-processor Dockerfile

Change COPY directive to include entire shared/python directory including setup.py, which is required for pip editable install.

Previously only copied glogger/ subdirectory, causing pip install to fail when trying to install -e ./shared/python.

🤖 Generated with Claude Code

Co-Authored-By: Claude Sonnet 4.5 noreply@anthropic.com EOF )”` Expected: [main ghi9012] fix: copy complete shared package in video-processor Dockerfile 1 file changed

Commit:

git add cloud-functions/video-processor/Dockerfile.test cloud-functions/video-processor/Dockerfile
git commit -m "fix: copy complete shared package in video-processor Dockerfile"

Task 4: Verify backend application starts successfully

Files:

  • Test: backend/app.py

Step 1: Create integration test script

#!/bin/bash
# Test that backend builds and starts without import errors
 
set -e
 
echo "Building backend Docker image..."
docker build -f backend/Dockerfile -t turbulence-backend:test .
 
echo "Starting backend container..."
docker run -d --name backend-test \
  -e MONGO_URI="mongodb://test:test@localhost:27017" \
  -e GCS_BUCKET_NAME="test-bucket" \
  -e GOOGLE_APPLICATION_CREDENTIALS_JSON="{}" \
  -p 8080:8080 \
  turbulence-backend:test
 
echo "Waiting for backend to start..."
sleep 5
 
echo "Testing health endpoint..."
curl -f http://localhost:8080/health || (docker logs backend-test && exit 1)
 
echo "Checking logs for import errors..."
docker logs backend-test 2>&1 | grep -i "attributeerror.*with_context" && exit 1 || true
 
echo "Stopping container..."
docker stop backend-test
docker rm backend-test
 
echo "Backend test passed!"

Expected: Integration test script created

Step 2: Run integration test without fixes (expect failure)

Run: cd /Users/nicholas/Documents/code/turbulence && chmod +x test-backend.sh && ./test-backend.sh Expected: AttributeError: ‘DefaultLogger’ object has no attribute ‘error_with_context’ Test fails due to missing methods

Step 3: Apply all fixes and rebuild

Run: cd /Users/nicholas/Documents/code/turbulence && docker build -f backend/Dockerfile -t turbulence-backend:test . Expected: Successfully built turbulence-backend:test All layers build successfully

Step 4: Run integration test with fixes (expect success)

Run: cd /Users/nicholas/Documents/code/turbulence && ./test-backend.sh Expected: Backend test passed! No AttributeError in logs Health endpoint returns 200

Step 5: Clean up test artifacts

Run: cd /Users/nicholas/Documents/code/turbulence && rm test-backend.sh && docker rmi turbulence-backend:test Expected: Test script and image removed


Task 5: Verify cloud function builds successfully

Files:

  • Test: cloud-functions/video-processor/main.py

Step 1: Create cloud function test script

#!/bin/bash
# Test that video-processor cloud function builds successfully
 
set -e
 
echo "Building video-processor Docker image..."
docker build -f cloud-functions/video-processor/Dockerfile -t video-processor:test .
 
echo "Verifying glogger imports..."
docker run --rm video-processor:test python -c "from glogger import get_component_logger; logger = get_component_logger('test'); logger.info('Test message'); print('SUCCESS')"
 
echo "Cleaning up..."
docker rmi video-processor:test
 
echo "Cloud function test passed!"

Expected: Test script created for cloud function

Step 2: Run cloud function build test without fix (expect failure)

Run: cd /Users/nicholas/Documents/code/turbulence && chmod +x test-cloud-function.sh && ./test-cloud-function.sh Expected: ERROR: Directory ’./shared/python’ is not installable Build fails

Step 3: Apply Dockerfile fix and rebuild

Run: cd /Users/nicholas/Documents/code/turbulence && docker build -f cloud-functions/video-processor/Dockerfile -t video-processor:test . Expected: Successfully built video-processor:test All layers build successfully

Step 4: Run cloud function test with fix (expect success)

Run: cd /Users/nicholas/Documents/code/turbulence && ./test-cloud-function.sh Expected: SUCCESS Cloud function test passed!

Step 5: Clean up test artifacts

Run: cd /Users/nicholas/Documents/code/turbulence && rm test-cloud-function.sh Expected: Test script removed


Task 6: Document the logger API usage patterns

Files:

  • Modify: shared/python/README.md

Step 1: Create test for README code examples

"""Test that README examples are valid."""
import pytest
from glogger import logger, get_component_logger
 
 
def test_readme_basic_usage():
    """Test basic usage examples from README."""
    # Standard API
    logger.info("User logged in", user_id="12345", ip_address="192.168.1.1")
    logger.error("Database connection failed", error_code="DB_001", retry_count=3)
    
    # Compatibility API
    logger.info_with_context("Request started", {"method": "GET", "path": "/api/users"})
    logger.error_with_context("Request failed", {"status_code": 500, "error": "Internal error"})
    
 
def test_readme_context_logger():
    """Test context logger examples from README."""
    request_logger = logger.with_context(request_id="abc-123", user_id="user-456")
    request_logger.info("Processing request")
    request_logger.error("Request failed")
 
 
def test_readme_component_logger():
    """Test component logger examples from README."""
    auth_logger = get_component_logger("auth-service")
    auth_logger.info("User authentication started")
    auth_logger.error("Authentication failed")

Expected: README examples test created

Step 2: Run README examples test (expect failure due to missing docs)

Run: cd /Users/nicholas/Documents/code/turbulence && source ~/Documents/venvs/turbulence/bin/activate && python -m pytest shared/python/tests/test_readme_examples.py -v Expected: Tests pass but README needs updates

Step 3: Update README with API usage documentation

Add a new section after existing usage examples:
 
## API Methods
 
The logger provides two API styles for compatibility:
 
### Standard API (Recommended)
 
Pass context as keyword arguments:
 
```python
from glogger import logger
 
# Log with context
logger.info("User logged in", user_id="12345", ip_address="192.168.1.1")
logger.error("Database error", error_code="DB_001", retry_count=3)

Compatibility API

Pass context as a dictionary (for backward compatibility):

from glogger import logger
 
# Log with context dictionary
logger.info_with_context("Request started", {"method": "GET", "path": "/api/users"})
logger.error_with_context("Request failed", {"status_code": 500})
logger.exception_with_context("Unhandled error", {"request_id": "abc-123"})

Context Logger Pattern

Create a logger with persistent context:

from glogger import logger
 
# Create logger with default context
request_logger = logger.with_context(request_id="abc-123", user_id="user-456")
 
# All logs include the default context
request_logger.info("Processing request")  # Includes request_id and user_id
request_logger.error("Request failed")      # Includes request_id and user_id

Deployment

When deploying with Docker, ensure you copy the complete shared package:

# Correct - copies entire package including setup.py
COPY shared/python/ ./shared/python/
 
# Incorrect - missing setup.py
COPY shared/python/glogger/ ./shared/python/glogger/

The requirements.txt uses editable install which requires setup.py:

-e ./shared/python

Expected: README updated with API documentation and deployment notes

**Step 4: Verify README examples still work**

Run: `cd /Users/nicholas/Documents/code/turbulence && source ~/Documents/venvs/turbulence/bin/activate && python -m pytest shared/python/tests/test_readme_examples.py -v`
Expected: All README example tests pass

**Step 5: Commit documentation updates**

Run: `cd /Users/nicholas/Documents/code/turbulence && git add shared/python/README.md shared/python/tests/test_readme_examples.py && git commit -m "$(cat <<'EOF'
docs: add API usage patterns and deployment guide

Document both standard and compatibility API methods.
Add deployment section explaining correct Dockerfile setup
for editable package installation.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
EOF
)"`
Expected: [main jkl3456] docs: add API usage patterns and deployment guide
 2 files changed

**Commit:**
```bash
git add shared/python/README.md
git commit -m "docs: add API usage patterns and deployment guide"