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
48 changes: 41 additions & 7 deletions python/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -556,20 +556,54 @@ SageMakerEnvVars.CUSTOM_SCRIPT_FILENAME
SageMakerEnvVars.SAGEMAKER_MODEL_PATH
```

### Debug Logging
### Logging Control

```python
from model_hosting_container_standards.logging_config import enable_debug_logging
The package provides centralized logging control using standard SageMaker environment variables.

**By default, the package uses ERROR level logging**, which effectively keeps it silent in production unless there are actual errors.

#### Log Level Configuration

```bash
# Set log level using SageMaker standard variable (recommended)
export SAGEMAKER_CONTAINER_LOG_LEVEL=DEBUG # or INFO, WARNING, ERROR (default)

# Alternative: Use generic LOG_LEVEL variable
export LOG_LEVEL=INFO # Falls back to this if SAGEMAKER_CONTAINER_LOG_LEVEL not set
```

#### Log Levels

# Enable detailed handler resolution logging
enable_debug_logging()
- **ERROR (default)**: Only errors are logged - effectively silent in normal operation
- **WARNING**: Errors and warnings
- **INFO**: Informational messages, warnings, and errors
- **DEBUG**: Detailed debug information including handler resolution

#### Log Format

All package logs use a consistent format:
```
[LEVEL] logger_name - filename:line: message
```

#### Examples

```bash
# Or via environment variable
export SAGEMAKER_CONTAINER_LOG_LEVEL=DEBUG
# Production: ERROR level by default (silent unless errors occur)
vllm serve model --dtype auto

# Development: Enable INFO level logging
SAGEMAKER_CONTAINER_LOG_LEVEL=INFO vllm serve model --dtype auto

# Debug mode: Enable detailed DEBUG logging
SAGEMAKER_CONTAINER_LOG_LEVEL=DEBUG vllm serve model --dtype auto

# Using alternative LOG_LEVEL variable
LOG_LEVEL=DEBUG vllm serve model --dtype auto
```

**Note**: These environment variables only control package logging. Your application's logging configuration is independent and unaffected.

## Testing

### Quick Endpoint Testing
Expand Down
2 changes: 1 addition & 1 deletion python/model_hosting_container_standards/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@
- FastAPI: from .common.fastapi import EnvVars, ENV_CONFIG
"""

__version__ = "0.1.7"
__version__ = "0.1.8"
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
"""

import importlib.util
import logging
from pathlib import Path
from typing import Any, List, Optional

Expand All @@ -36,8 +35,7 @@
HandlerNotFoundError,
ModuleLoadError,
)

logger = logging.getLogger(__name__)
from model_hosting_container_standards.logging_config import logger


class FileLoader:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
import logging
from typing import Any, Callable, Dict, List, Optional

from model_hosting_container_standards.exceptions import (
HandlerFileNotFoundError,
HandlerNotCallableError,
HandlerNotFoundError,
)
from model_hosting_container_standards.logging_config import logger

from ..handler.spec import HandlerSpec
from .file_loader import FileLoader
from .module_loader import ModuleLoader

logger = logging.getLogger(__name__)


class FunctionLoader:
"""Unified function loader supporting multiple formats.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,13 @@
"""

import importlib
import logging
from typing import Any, Optional

from model_hosting_container_standards.exceptions import (
HandlerNotFoundError,
ModuleLoadError,
)

logger = logging.getLogger(__name__)
from model_hosting_container_standards.logging_config import logger


class ModuleLoader:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import logging
from dataclasses import dataclass
from typing import Callable, List, Optional

from fastapi import APIRouter, FastAPI
from fastapi.routing import APIRoute

from ...logging_config import logger
from ..handler import handler_registry

logger = logging.getLogger(__name__)


def normalize_prefix(prefix: str) -> str:
"""Normalize a URL prefix to ensure consistent path handling.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ def get_customer_script_handler(self, handler_type: str):
```
"""

import logging
from abc import ABC, abstractmethod
from typing import Any, Callable, Optional, Union

Expand All @@ -44,11 +43,10 @@ def get_customer_script_handler(self, handler_type: str):
HandlerResolutionError,
InvalidHandlerSpecError,
)
from model_hosting_container_standards.logging_config import logger

from .registry import handler_registry

logger = logging.getLogger(__name__)


class HandlerConfig(ABC):
"""Abstract base class for handler configuration.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import logging
from typing import Any, Callable, Dict, Optional

from fastapi import Request

from model_hosting_container_standards.common import BaseApiTransform
from model_hosting_container_standards.common.handler import handler_registry

logger = logging.getLogger(__name__)
from model_hosting_container_standards.logging_config import logger


def _resolve_transforms(
Expand Down
13 changes: 10 additions & 3 deletions python/model_hosting_container_standards/logging_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,21 @@


def get_logger(name: str = "model_hosting_container_standards") -> logging.Logger:
"""Get a configured logger for the package."""
"""Get a configured logger for the package.

The logger uses SAGEMAKER_CONTAINER_LOG_LEVEL (or LOG_LEVEL) to determine the log level.
If not set, defaults to ERROR level, which effectively disables most package logging.

Returns:
Configured logger instance for the package.
"""
logger = logging.getLogger(name)

# Only configure if not already configured
if not logger.handlers:
# Get log level from environment or default to INFO
# Get log level from environment, default to ERROR (effectively disabled)
level = os.getenv(
"SAGEMAKER_CONTAINER_LOG_LEVEL", os.getenv("LOG_LEVEL", "INFO")
"SAGEMAKER_CONTAINER_LOG_LEVEL", os.getenv("LOG_LEVEL", "ERROR")
)

# Set up handler with consistent format
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,14 @@
- Missing handlers return None (graceful degradation)
"""

import logging
from typing import Any, Callable, Optional, Union

from ..common.handler.registry import handler_registry
from ..common.handler.resolver import GenericHandlerResolver, HandlerConfig
from ..exceptions import HandlerFileNotFoundError, HandlerNotFoundError
from ..logging_config import logger
from .sagemaker_loader import SageMakerFunctionLoader

logger = logging.getLogger(__name__)


class SageMakerHandlerConfig(HandlerConfig):
"""SageMaker-specific handler configuration."""
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
import logging

from model_hosting_container_standards.common.transforms.base_factory import (
create_transform_decorator,
)

from .transforms import resolve_lora_transform

logger = logging.getLogger(__name__)


def create_lora_transform_decorator(handler_type: str):
return create_transform_decorator(handler_type, resolve_lora_transform)
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import logging
from typing import List

from ....logging_config import logger
from ..constants import LoRAHandlerType
from .inject_to_body import InjectToBodyApiTransform
from .register import RegisterLoRAApiTransform
from .unregister import UnregisterLoRAApiTransform

logger = logging.getLogger(__name__)


def resolve_lora_transform(handler_type: str) -> type:
"""Get the appropriate transformer class based on the LoRA handler type.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
import logging
from typing import Optional

from fastapi import APIRouter

# Import routing utilities (generic)
from ..common.fastapi.routing import RouteConfig, create_router
from ..logging_config import logger

# Import LoRA-specific route configuration
from .lora.routes import get_lora_route_config

logger = logging.getLogger(__name__)


def get_sagemaker_route_config(handler_type: str) -> Optional[RouteConfig]:
"""Get route configuration for SageMaker handler types.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
import logging
from datetime import datetime, timezone
from http import HTTPStatus

from fastapi import Request, Response
from fastapi.exceptions import HTTPException

from ...logging_config import logger
from .manager import SessionManager
from .models import SageMakerSessionHeader, SessionRequestType
from .utils import get_session_id_from_request

logger = logging.getLogger(__name__)


def get_handler_for_request_type(request_type: SessionRequestType):
"""Map session request type to the appropriate handler function.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import json
import logging
from http import HTTPStatus
from typing import Optional

Expand All @@ -13,8 +12,6 @@
from .models import SessionRequest
from .utils import get_session, get_session_id_from_request

logger = logging.getLogger(__name__)


def _parse_session_request(request_data: dict) -> Optional[SessionRequest]:
"""Parse and validate if request is a session management request.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import logging
from http import HTTPStatus

from fastapi import Request
from fastapi.exceptions import HTTPException

from ...logging_config import logger
from .manager import SessionManager
from .models import SageMakerSessionHeader

logger = logging.getLogger(__name__)


def get_session_id_from_request(raw_request: Request):
"""Extract the session ID from the request headers.
Expand Down
2 changes: 1 addition & 1 deletion python/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "model-hosting-container-standards"
version = "0.1.7"
version = "0.1.8"
description = "Python toolkit for standardized model hosting container implementations with Amazon SageMaker integration"
authors = ["Amazon Web Services"]
readme = "README.md"
Expand Down
Loading