Add CI/CD pipeline, logging enhancements, and release management
Lint Code / lint (push) Failing after 2m2s
CI/CD Pipeline / lint (push) Successful in 0s
Run Tests / test (3.12) (push) Successful in 54s
CI/CD Pipeline / build-and-release (push) Has been cancelled
CI/CD Pipeline / test (push) Has been cancelled
CI/CD Pipeline / notify (push) Has been cancelled
Run Tests / test (3.13) (push) Has been cancelled
Lint Code / lint (push) Failing after 2m2s
CI/CD Pipeline / lint (push) Successful in 0s
Run Tests / test (3.12) (push) Successful in 54s
CI/CD Pipeline / build-and-release (push) Has been cancelled
CI/CD Pipeline / test (push) Has been cancelled
CI/CD Pipeline / notify (push) Has been cancelled
Run Tests / test (3.13) (push) Has been cancelled
- Create a GitHub Actions workflow for testing with Python 3.12 and 3.13. - Update Makefile to include release management commands and pipeline checks. - Document the CI/CD pipeline structure and usage in PIPELINE.md. - Add structlog for structured logging and enhance logging utilities. - Implement release management script for automated versioning and tagging. - Modify logging configuration to support structured logging and improved formatting. - Update dependencies in pyproject.toml and poetry.lock to include structlog. - Enhance access logging in server and middleware to include structured data.
This commit is contained in:
+26
-10
@@ -48,7 +48,15 @@ class PyServeMiddleware:
|
||||
status_code = response.status_code
|
||||
process_time = round((time.time() - start_time) * 1000, 2)
|
||||
|
||||
self.access_logger.info(f"{client_ip} - {method} {path} - {status_code} - {process_time}ms")
|
||||
self.access_logger.info(
|
||||
"HTTP request",
|
||||
client_ip=client_ip,
|
||||
method=method,
|
||||
path=path,
|
||||
status_code=status_code,
|
||||
process_time_ms=process_time,
|
||||
user_agent=request.headers.get("user-agent", "")
|
||||
)
|
||||
|
||||
await response(scope, receive, send)
|
||||
|
||||
@@ -64,7 +72,7 @@ class PyServeServer:
|
||||
|
||||
def _setup_logging(self) -> None:
|
||||
self.config.setup_logging()
|
||||
logger.info("PyServe server initialized")
|
||||
logger.info("PyServe server initialized", version=__version__)
|
||||
|
||||
def _load_extensions(self) -> None:
|
||||
for ext_config in self.config.extensions:
|
||||
@@ -106,7 +114,8 @@ class PyServeServer:
|
||||
ext_metrics = getattr(extension, 'get_metrics')()
|
||||
metrics.update(ext_metrics)
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting metrics from {type(extension).__name__}: {e}")
|
||||
logger.error("Error getting metrics from extension",
|
||||
extension=type(extension).__name__, error=str(e))
|
||||
|
||||
import json
|
||||
return Response(
|
||||
@@ -122,11 +131,11 @@ class PyServeServer:
|
||||
return None
|
||||
|
||||
if not Path(self.config.ssl.cert_file).exists():
|
||||
logger.error(f"SSL certificate not found: {self.config.ssl.cert_file}")
|
||||
logger.error("SSL certificate not found", cert_file=self.config.ssl.cert_file)
|
||||
return None
|
||||
|
||||
if not Path(self.config.ssl.key_file).exists():
|
||||
logger.error(f"SSL key not found: {self.config.ssl.key_file}")
|
||||
logger.error("SSL key not found", key_file=self.config.ssl.key_file)
|
||||
return None
|
||||
|
||||
try:
|
||||
@@ -138,7 +147,7 @@ class PyServeServer:
|
||||
logger.info("SSL context created successfully")
|
||||
return context
|
||||
except Exception as e:
|
||||
logger.error(f"Error creating SSL context: {e}")
|
||||
logger.error("Error creating SSL context", error=str(e), exc_info=True)
|
||||
return None
|
||||
|
||||
def run(self) -> None:
|
||||
@@ -167,7 +176,12 @@ class PyServeServer:
|
||||
else:
|
||||
protocol = "http"
|
||||
|
||||
logger.info(f"Starting PyServe server at {protocol}://{self.config.server.host}:{self.config.server.port}")
|
||||
logger.info(
|
||||
"Starting PyServe server",
|
||||
protocol=protocol,
|
||||
host=self.config.server.host,
|
||||
port=self.config.server.port
|
||||
)
|
||||
|
||||
try:
|
||||
assert self.app is not None, "App not initialized"
|
||||
@@ -175,7 +189,7 @@ class PyServeServer:
|
||||
except KeyboardInterrupt:
|
||||
logger.info("Received shutdown signal")
|
||||
except Exception as e:
|
||||
logger.error(f"Error starting server: {e}")
|
||||
logger.error("Error starting server", error=str(e), exc_info=True)
|
||||
finally:
|
||||
self.shutdown()
|
||||
|
||||
@@ -193,6 +207,7 @@ class PyServeServer:
|
||||
log_level="critical",
|
||||
access_log=False,
|
||||
use_colors=False,
|
||||
backlog=self.config.server.backlog if self.config.server.backlog else 2048,
|
||||
)
|
||||
|
||||
server = uvicorn.Server(config)
|
||||
@@ -215,7 +230,7 @@ class PyServeServer:
|
||||
|
||||
for directory in directories:
|
||||
Path(directory).mkdir(parents=True, exist_ok=True)
|
||||
logger.debug(f"Created/checked directory: {directory}")
|
||||
logger.debug("Created/checked directory", directory=directory)
|
||||
|
||||
def shutdown(self) -> None:
|
||||
logger.info("Shutting down PyServe server")
|
||||
@@ -238,7 +253,8 @@ class PyServeServer:
|
||||
ext_metrics = getattr(extension, 'get_metrics')()
|
||||
metrics.update(ext_metrics)
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting metrics from {type(extension).__name__}: {e}")
|
||||
logger.error("Error getting metrics from extension",
|
||||
extension=type(extension).__name__, error=str(e))
|
||||
|
||||
return metrics
|
||||
|
||||
|
||||
Reference in New Issue
Block a user