mirror of https://github.com/langgenius/dify.git
155 lines
4.4 KiB
Python
155 lines
4.4 KiB
Python
import logging
|
|
import time
|
|
|
|
from opentelemetry.trace import get_current_span
|
|
from opentelemetry.trace.span import INVALID_SPAN_ID, INVALID_TRACE_ID
|
|
|
|
from configs import dify_config
|
|
from contexts.wrapper import RecyclableContextVar
|
|
from core.logging.context import init_request_context
|
|
from dify_app import DifyApp
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
# ----------------------------
|
|
# Application Factory Function
|
|
# ----------------------------
|
|
def create_flask_app_with_configs() -> DifyApp:
|
|
"""
|
|
create a raw flask app
|
|
with configs loaded from .env file
|
|
"""
|
|
dify_app = DifyApp(__name__)
|
|
dify_app.config.from_mapping(dify_config.model_dump())
|
|
dify_app.config["RESTX_INCLUDE_ALL_MODELS"] = True
|
|
|
|
# add before request hook
|
|
@dify_app.before_request
|
|
def before_request():
|
|
# Initialize logging context for this request
|
|
init_request_context()
|
|
RecyclableContextVar.increment_thread_recycles()
|
|
|
|
# add after request hook for injecting trace headers from OpenTelemetry span context
|
|
# Only adds headers when OTEL is enabled and has valid context
|
|
@dify_app.after_request
|
|
def add_trace_headers(response):
|
|
try:
|
|
span = get_current_span()
|
|
ctx = span.get_span_context() if span else None
|
|
|
|
if not ctx or not ctx.is_valid:
|
|
return response
|
|
|
|
# Inject trace headers from OTEL context
|
|
if ctx.trace_id != INVALID_TRACE_ID and "X-Trace-Id" not in response.headers:
|
|
response.headers["X-Trace-Id"] = format(ctx.trace_id, "032x")
|
|
if ctx.span_id != INVALID_SPAN_ID and "X-Span-Id" not in response.headers:
|
|
response.headers["X-Span-Id"] = format(ctx.span_id, "016x")
|
|
|
|
except Exception:
|
|
# Never break the response due to tracing header injection
|
|
logger.warning("Failed to add trace headers to response", exc_info=True)
|
|
return response
|
|
|
|
# Capture the decorator's return value to avoid pyright reportUnusedFunction
|
|
_ = before_request
|
|
_ = add_trace_headers
|
|
|
|
return dify_app
|
|
|
|
|
|
def create_app() -> DifyApp:
|
|
start_time = time.perf_counter()
|
|
app = create_flask_app_with_configs()
|
|
initialize_extensions(app)
|
|
end_time = time.perf_counter()
|
|
if dify_config.DEBUG:
|
|
logger.info("Finished create_app (%s ms)", round((end_time - start_time) * 1000, 2))
|
|
return app
|
|
|
|
|
|
def initialize_extensions(app: DifyApp):
|
|
from extensions import (
|
|
ext_app_metrics,
|
|
ext_blueprints,
|
|
ext_celery,
|
|
ext_code_based_extension,
|
|
ext_commands,
|
|
ext_compress,
|
|
ext_database,
|
|
ext_forward_refs,
|
|
ext_hosting_provider,
|
|
ext_import_modules,
|
|
ext_logging,
|
|
ext_login,
|
|
ext_logstore,
|
|
ext_mail,
|
|
ext_migrate,
|
|
ext_orjson,
|
|
ext_otel,
|
|
ext_proxy_fix,
|
|
ext_redis,
|
|
ext_request_logging,
|
|
ext_sentry,
|
|
ext_session_factory,
|
|
ext_set_secretkey,
|
|
ext_storage,
|
|
ext_timezone,
|
|
ext_warnings,
|
|
)
|
|
|
|
extensions = [
|
|
ext_timezone,
|
|
ext_logging,
|
|
ext_warnings,
|
|
ext_import_modules,
|
|
ext_orjson,
|
|
ext_forward_refs,
|
|
ext_set_secretkey,
|
|
ext_compress,
|
|
ext_code_based_extension,
|
|
ext_database,
|
|
ext_app_metrics,
|
|
ext_migrate,
|
|
ext_redis,
|
|
ext_storage,
|
|
ext_logstore, # Initialize logstore after storage, before celery
|
|
ext_celery,
|
|
ext_login,
|
|
ext_mail,
|
|
ext_hosting_provider,
|
|
ext_sentry,
|
|
ext_proxy_fix,
|
|
ext_blueprints,
|
|
ext_commands,
|
|
ext_otel,
|
|
ext_request_logging,
|
|
ext_session_factory,
|
|
]
|
|
for ext in extensions:
|
|
short_name = ext.__name__.split(".")[-1]
|
|
is_enabled = ext.is_enabled() if hasattr(ext, "is_enabled") else True
|
|
if not is_enabled:
|
|
if dify_config.DEBUG:
|
|
logger.info("Skipped %s", short_name)
|
|
continue
|
|
|
|
start_time = time.perf_counter()
|
|
ext.init_app(app)
|
|
end_time = time.perf_counter()
|
|
if dify_config.DEBUG:
|
|
logger.info("Loaded %s (%s ms)", short_name, round((end_time - start_time) * 1000, 2))
|
|
|
|
|
|
def create_migrations_app():
|
|
app = create_flask_app_with_configs()
|
|
from extensions import ext_database, ext_migrate
|
|
|
|
# Initialize only required extensions
|
|
ext_database.init_app(app)
|
|
ext_migrate.init_app(app)
|
|
|
|
return app
|