Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PFS] Start pfs in foreground and log in terminal and file in debug mode #2756

Merged
merged 9 commits into from
Apr 12, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
74 changes: 41 additions & 33 deletions src/promptflow-devkit/promptflow/_cli/_pf/_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,42 +157,35 @@ def start_service(args):
port = args.port
if args.debug:
os.environ[PF_SERVICE_DEBUG] = "true"

if is_run_from_built_binary():
# For msi installer/executable, use sdk api to start pfs since it's not supported to invoke waitress by cli
# directly after packaged by Pyinstaller.
parent_dir = os.path.dirname(sys.executable)
output_path = os.path.join(parent_dir, "output.txt")
with redirect_stdout_to_file(output_path):
port = validate_port(port, args.force)
global app
if app is None:
app, _ = create_app()
if os.environ.get(PF_SERVICE_DEBUG) == "true":
app.logger.setLevel(logging.DEBUG)
else:
app.logger.setLevel(logging.INFO)
message = f"Starting Prompt Flow Service on {port}, version: {get_pfs_version()}."
app.logger.info(message)
print(message)
sys.stdout.flush()
if not is_run_from_built_binary():
YingChen1996 marked this conversation as resolved.
Show resolved Hide resolved
add_executable_script_to_env_path()
port = _prepare_app_for_foreground_service(port, args.force)
waitress.serve(app, host="127.0.0.1", port=port, threads=PF_SERVICE_WORKER_NUM)
else:
port = validate_port(port, args.force)
add_executable_script_to_env_path()
# Start a pfs process using detach mode. It will start a new process and create a new app. So we use environment
# variable to pass the debug mode, since it will inherit parent process environment variable.
if platform.system() == "Windows":
_start_background_service_on_windows(port)
else:
_start_background_service_on_unix(port)
is_healthy = check_pfs_service_status(port)
if is_healthy:
message = f"Start Promptflow Service on port {port}, version: {get_pfs_version()}."
print(message)
logger.info(message)
if is_run_from_built_binary():
# For msi installer/executable, use sdk api to start pfs since it's not supported to invoke waitress by cli
# directly after packaged by Pyinstaller.
parent_dir = os.path.dirname(sys.executable)
output_path = os.path.join(parent_dir, "output.txt")
with redirect_stdout_to_file(output_path):
port = _prepare_app_for_foreground_service(port, args.force)
waitress.serve(app, host="127.0.0.1", port=port, threads=PF_SERVICE_WORKER_NUM)
else:
logger.warning(f"Promptflow service start failed in {port}. {hint_stop_before_upgrade}")
port = validate_port(port, args.force)
add_executable_script_to_env_path()
# Start a pfs process using detach mode. It will start a new process and create a new app. So we use
# environment variable to pass the debug mode, since it will inherit parent process environment variable.
if platform.system() == "Windows":
_start_background_service_on_windows(port)
else:
_start_background_service_on_unix(port)
is_healthy = check_pfs_service_status(port)
if is_healthy:
message = f"Start Promptflow Service on port {port}, version: {get_pfs_version()}."
print(message)
logger.info(message)
else:
logger.warning(f"Promptflow service start failed in {port}. {hint_stop_before_upgrade}")


def validate_port(port, force_start):
Expand Down Expand Up @@ -238,6 +231,21 @@ def redirect_stdout_to_file(path):
sys.stderr = old_stderr


def _prepare_app_for_foreground_service(port, force_start):
port = validate_port(port, force_start)
global app
if app is None:
app, _ = create_app()
if os.environ.get(PF_SERVICE_DEBUG) == "true":
app.logger.setLevel(logging.DEBUG)
else:
app.logger.setLevel(logging.INFO)
message = f"Starting Prompt Flow Service on {port}, version: {get_pfs_version()}."
app.logger.info(message)
print(message)
return port


def _start_background_service_on_windows(port):
try:
import win32api
Expand Down
13 changes: 13 additions & 0 deletions src/promptflow-devkit/promptflow/_sdk/_service/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# ---------------------------------------------------------
import logging
import os
import threading
import time
from datetime import datetime, timedelta
Expand All @@ -14,6 +15,7 @@

from promptflow._sdk._constants import (
HOME_PROMPT_FLOW_DIR,
PF_SERVICE_DEBUG,
PF_SERVICE_HOUR_TIMEOUT,
PF_SERVICE_LOG_FILE,
PF_SERVICE_MONITOR_SECOND,
Expand Down Expand Up @@ -98,8 +100,19 @@ def create_app():
handler = RotatingFileHandler(filename=log_file, maxBytes=1_000_000, backupCount=1)
formatter = logging.Formatter("[%(asctime)s][%(name)s][%(levelname)s] - %(message)s")
handler.setFormatter(formatter)

YingChen1996 marked this conversation as resolved.
Show resolved Hide resolved
# Create a stream handler to output logs to the terminal
stream_handler = logging.StreamHandler()
stream_handler.setFormatter(formatter)

# Set app logger to the only one RotatingFileHandler to avoid duplicate logs
app.logger.handlers = [handler]
if os.environ.get(PF_SERVICE_DEBUG) == "true":
# Set app logger to use both the rotating file handler and the stream handler in debug mode
app.logger.handlers.append(stream_handler)

# Prevent logs from being handled by the root logger
app.logger.propagate = False

# Basic error handler
@api.errorhandler(Exception)
Expand Down
Loading