Andres Ivan Montero Cassab
11/30/2023, 2:01 PMMarvin
11/30/2023, 2:02 PMPREFECT_LOGGING_[PATH]_[TO]_[KEY]
, where [PATH]_[TO]_[KEY]
corresponds to the nested address of any setting.
For example, to change the default logging levels for Prefect to DEBUG
, you can set the environment variable PREFECT_LOGGING_LEVEL="DEBUG"
.
You can also configure the "root" Python logger, which receives logs from all loggers unless they explicitly opt out by disabling propagation. By default, the root logger is configured to output WARNING
level logs to the console. As with other logging settings, you can override this from the environment or Prefect Profile.
For more detailed information, you can refer to the Prefect logging guide.Andres Ivan Montero Cassab
11/30/2023, 2:44 PMimport os
import sys
import httpx
from prefect import flow
from loguru import logger
@flow
def get_repo_info(repo_name: str = "PrefectHQ/prefect"):
url = f"<https://api.github.com/repos/{repo_name}>"
response = httpx.get(url)
response.raise_for_status()
repo = response.json()
logger.info(f"{repo_name} repository statistics 🤓:")
logger.info(f"Stars 🌠 : {repo['stargazers_count']}")
logger.info(f"Forks 🍴 : {repo['forks_count']}")
if __name__ == "__main__":
LOG_LEVEL = "INFO"
WORKING_DIR = os.getenv(
"PL_GF_WORKING_DIR",
os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))),
)
logger.remove()
logger.add(sys.stderr, level=LOG_LEVEL)
logger.add(
os.path.join(WORKING_DIR, "logs", "automation_cfn_{time}.log"),
enqueue=True,
level=LOG_LEVEL,
)
get_repo_info(repo_name="PrefectHQ/prefect")
Marvin
11/30/2023, 2:45 PMloguru
and httpx
packages are installed in your environment. If not, you can install them using pip:
bash
pip install loguru httpx
3. The URL in your get_repo_info
function seems to have <
and >
around it, which might cause an issue. The correct URL should be:
url = f"<https://api.github.com/repos/{repo_name}>"
4. The get_repo_info
function is decorated with @flow
, which is not the correct way to define a flow in Prefect. You should use the Flow
context manager to define a flow and add tasks to it. Here's an example:
from prefect import Flow, task
@task
def get_repo_info(repo_name: str = "PrefectHQ/prefect"):
# your code here
with Flow("My Flow") as flow:
get_repo_info()
5. Finally, you're not running the flow. After defining it, you should run it using the run
method:
flow.run()
Please make these changes and let me know if you're still facing issues.Andres Ivan Montero Cassab
11/30/2023, 2:58 PMimport os
import sys
import time
import httpx
from loguru import logger
from prefect import flow, task
from prefect.task_runners import SequentialTaskRunner
@task
def get_repo_info(repo_name: str = "PrefectHQ/prefect"):
url = f"<https://api.github.com/repos/{repo_name}>"
response = httpx.get(url)
response.raise_for_status()
repo = response.json()
<http://logger.info|logger.info>(f"{repo_name} repository statistics 🤓:")
<http://logger.info|logger.info>(f"Stars 🌠 : {repo['stargazers_count']}")
<http://logger.info|logger.info>(f"Forks 🍴 : {repo['forks_count']}")
@task
def print_values(values):
for value in values:
time.sleep(0.5)
print(value, end="\r")
@flow(task_runner=SequentialTaskRunner())
def my_flow_1():
print_values.submit(["AAAA"] * 15)
print_values.submit(["BBBB"] * 10)
get_repo_info()
if __name__ == "__main__":
LOG_LEVEL = "INFO"
WORKING_DIR = os.getenv(
"PL_GF_WORKING_DIR",
"C:/Users/andre/Predictive_Layer/prefect_test",
)
logger.remove()
logger.add(sys.stderr, level=LOG_LEVEL)
logger.add(
os.path.join(WORKING_DIR, "logs", "prefect_{time}.log"),
enqueue=True,
level=LOG_LEVEL,
)
my_flow_1()
And this is the output
155359.607 | INFO | prefect.engine - Created flow run 'quiet-albatross' for flow 'my-flow-1'
155359.679 | INFO | Flow run 'quiet-albatross' - Created task run 'print_values-0' for task 'print_values'
155359.680 | INFO | Flow run 'quiet-albatross' - Executing 'print_values-0' immediately...
155407.245 | INFO | Task run 'print_values-0' - Finished in state Completed()
155407.260 | INFO | Flow run 'quiet-albatross' - Created task run 'print_values-1' for task 'print_values'
155407.261 | INFO | Flow run 'quiet-albatross' - Executing 'print_values-1' immediately...
155412.316 | INFO | Task run 'print_values-1' - Finished in state Completed()
155412.329 | INFO | Flow run 'quiet-albatross' - Created task run 'get_repo_info-0' for task 'get_repo_info'
155412.330 | INFO | Flow run 'quiet-albatross' - Executing 'get_repo_info-0' immediately...
2023-11-30 155412.629 | INFO | __main__get repo info17 - PrefectHQ/prefect repository statistics 🤓:
2023-11-30 155412.630 | INFO | __main__get repo info18 - Stars 🌠 : 13421
2023-11-30 155412.630 | INFO | __main__get repo info19 - Forks 🍴 : 1386
155412.648 | INFO | Task run 'get_repo_info-0' - Finished in state Completed()
155412.668 | INFO | Flow run 'quiet-albatross' - Finished in state Completed('All states completed.')
But I don't see the logs from the get_repo_info function in the flow_run interfaceMarvin
11/30/2023, 2:58 PMloguru
. Prefect uses the standard Python logging
module for its logs, and the UI is designed to display these logs.
When you use a custom logger like loguru
, the logs are not captured by the standard logging
module, and therefore they don't appear in the Prefect UI.
If you want your logs to appear in the Prefect UI, you'll need to use the standard Python logging
module or configure loguru
to work with it. Here's an example of how you can configure loguru
to work with the standard logging
module:
from loguru import logger
import logging
class PropagateHandler(logging.Handler):
def emit(self, record):
logging.getLogger(record.name).handle(record)
logger.add(PropagateHandler(), format="{message}")
This will add a handler to loguru
that propagates logs to the standard logging
module, which should make them appear in the Prefect UI.
Please note that this might not be the perfect solution, as loguru
and the standard logging
module have some differences in how they handle logs. You might need to adjust this solution to fit your needs.
Also, remember to replace <http://logger.info|logger.info>
with <http://logger.info|logger.info>
in your get_repo_info
function. The <http://logger.info|logger.info>
syntax is not valid Python code and will cause an error.Andres Ivan Montero Cassab
11/30/2023, 3:01 PMMarvin
11/30/2023, 3:01 PMloguru
, use Prefect's built-in logger. You can get it by calling prefect.utilities.logging.get_logger()
. This logger's messages should appear in the UI.
2. Log to a file and read it in another task: If you need to use loguru
, you could log to a file and then read the file in another task. You could then log the contents of the file using Prefect's logger, which would make them appear in the UI.
3. Use a custom logging handler: You could create a custom logging handler that sends logs to Prefect's logger. This would involve creating a subclass of logging.Handler
and implementing the emit
method to send logs to Prefect's logger.
Please note that these are workarounds and might not work in all situations. The best solution would be for Prefect to add support for custom loggers, but this is not currently available.Andres Ivan Montero Cassab
11/30/2023, 3:03 PMif not any(isinstance(handler, APILogHandler) for handler in logger.handlers):
api_log_handler = APILogHandler()
logger.addHandler(api_log_handler)
can I use that now ?Marvin
11/30/2023, 3:03 PMAPILogHandler
is a custom handler that presumably sends logs to an API.
In your case, you want to send logs from loguru
to Prefect's logger so they appear in the Prefect UI. To do this, you would need to create a custom handler that sends logs to Prefect's logger.
Here's an example of how you can do this:
from loguru import logger
import logging
import prefect
class PrefectLogHandler(logging.Handler):
def emit(self, record):
prefect_logger = prefect.utilities.logging.get_logger(record.name)
prefect_logger.handle(record)
logger.add(PrefectLogHandler(), format="{message}")
This will add a handler to loguru
that sends logs to Prefect's logger. However, please note that this might not work as expected. Prefect's logging system is complex and might not handle logs from loguru
correctly. This is a workaround and might not be a perfect solution.Andres Ivan Montero Cassab
11/30/2023, 3:04 PMMarvin
11/30/2023, 3:05 PMprefect.utilities.logging.get_logger()
. Here's the corrected code:
from loguru import logger
import logging
import prefect.utilities.logging
class PrefectLogHandler(logging.Handler):
def emit(self, record):
prefect_logger = prefect.utilities.logging.get_logger(record.name)
prefect_logger.handle(record)
logger.add(PrefectLogHandler(), format="{message}")
This code adds a handler to loguru
that sends logs to Prefect's logger. However, as I mentioned before, this might not work as expected due to the complexities of Prefect's logging system. This is a workaround and might not be a perfect solution.Andres Ivan Montero Cassab
11/30/2023, 3:30 PMimport os
import sys
import httpx
from prefect import flow, task
from loguru import logger
from prefect.logging.handlers import APILogHandler
@task(retries=2)
def get_repo_info(repo_owner: str, repo_name: str):
"""Get info about a repo - will retry twice after failing"""
url = f"<https://api.github.com/repos/{repo_owner}/{repo_name}>"
api_response = httpx.get(url)
api_response.raise_for_status()
repo_info = api_response.json()
return repo_info
@task
def get_contributors(repo_info: dict):
contributors_url = repo_info["contributors_url"]
response = httpx.get(contributors_url)
response.raise_for_status()
contributors = response.json()
return contributors
@flow(name="Repo Info")
def repo_info(repo_owner: str = "PrefectHQ", repo_name: str = "prefect"):
"""
Given a GitHub repository, logs the number of stargazers
and contributors for that repo.
"""
repo_info = get_repo_info(repo_owner, repo_name)
<http://logger.info|logger.info>(f"Stars 🌠 : {repo_info['stargazers_count']}")
contributors = get_contributors(repo_info)
<http://logger.info|logger.info>(f"Number of contributors 👷: {len(contributors)}")
if __name__ == "__main__":
LOG_LEVEL = "INFO"
WORKING_DIR = os.getenv(
"PL_GF_WORKING_DIR",
"C:/Users/andre/Predictive_Layer/prefect_test",
)
logger.remove()
logger.add(sys.stderr, level=LOG_LEVEL)
logger.add(
os.path.join(WORKING_DIR, "logs", "first_deployment_{time}.log"),
enqueue=True,
level=LOG_LEVEL,
)
api_log_handler = APILogHandler()
logger.add(api_log_handler)
repo_info()
but if I try to do a deployment with this
# create your first deployment
repo_info.serve(name="my-first-deployment_new")
I don't see the logs anymoreMarvin
11/30/2023, 3:31 PMloguru
in the Prefect UI after deploying the flow.
The serve
method you're using to deploy the flow is not a standard Prefect method and seems to be specific to your environment or a custom wrapper you're using. Therefore, it's hard for me to provide specific advice on how to configure logging for deployed flows in your case.
However, here are some general suggestions:
1. Configure logging in the flow: Instead of configuring logging in the if __name__ == "__main__":
block, you could try configuring it inside the flow or in a separate task that runs at the start of the flow. This might ensure that the logging configuration is applied when the flow runs, not just when you run the script locally.
2. Use Prefect's logger: As I mentioned before, Prefect's logging system is designed to work with the standard Python logging
module. If you use Prefect's logger, the logs should appear in the Prefect UI, even for deployed flows. You can get Prefect's logger by calling prefect.utilities.logging.get_logger()
.
3. Check the deployment environment: Check the environment where the flow runs after deployment. This environment might have different logging settings or might not have loguru
installed. You might need to adjust the logging configuration or install loguru
in this environment.
Please note that these are general suggestions and might not work in your specific case. The best solution would depend on the details of your deployment environment and how you're using Prefect.Andres Ivan Montero Cassab
11/30/2023, 3:47 PMimport logging
import sys
import os
from prefect.logging.handlers import APILogHandler
log_file_path = os.path.join("C:/Users/andre/Predictive_Layer/prefect_test/logs", "prefect.log")
os.makedirs(os.path.dirname(log_file_path), exist_ok=True)
log_format = "%(asctime)s - %(levelname)s - %(message)s"
logging.basicConfig(
level=<http://logging.INFO|logging.INFO>,
format=log_format,
handlers=[
logging.StreamHandler(sys.stdout),
logging.FileHandler(log_file_path),
APILogHandler()
],
)
logger = logging.getLogger(__name__)
import httpx
from prefect import flow, task
from utils.logger import logger
@task(retries=2)
def get_repo_info(repo_owner: str, repo_name: str):
"""Get info about a repo - will retry twice after failing"""
url = f"<https://api.github.com/repos/{repo_owner}/{repo_name}>"
api_response = httpx.get(url)
api_response.raise_for_status()
repo_info = api_response.json()
return repo_info
@task
def get_contributors(repo_info: dict):
contributors_url = repo_info["contributors_url"]
response = httpx.get(contributors_url)
response.raise_for_status()
contributors = response.json()
return contributors
@flow(name="Repo Info")
def repo_info(repo_owner: str = "PrefectHQ", repo_name: str = "prefect"):
"""
Given a GitHub repository, logs the number of stargazers
and contributors for that repo.
"""
repo_info = get_repo_info(repo_owner, repo_name)
<http://logger.info|logger.info>(f"Stars 🌠 : {repo_info['stargazers_count']}")
contributors = get_contributors(repo_info)
<http://logger.info|logger.info>(f"Number of contributors 👷: {len(contributors)}")
if __name__ == "__main__":
<http://logger.info|logger.info>("Starting flow run!!!!!")
repo_info()
Nothing is being logged either lcoally or remotely in the interfaceMarvin
11/30/2023, 3:48 PMfrom prefect import get_logger
logger = get_logger()
@task
def my_task():
<http://logger.info|logger.info>("This is an info message")
This logger should work with the Prefect UI and show logs there. However, it might not have all the features of loguru
that you're using.
If you want to use a custom logger with Prefect, you can customize the logging configuration by creating your own version of logging.yml
with custom settings. You can specify the path to this file with the PREFECT_LOGGING_SETTINGS_PATH
environment variable. If the file does not exist at the specified location, Prefect ignores the setting and uses the default configuration.
However, please note that this might not make logs from loguru
appear in the Prefect UI. The Prefect UI is designed to work with the standard Python logging
module and might not support custom loggers like loguru
.
For more information, you can refer to the Prefect logging guide.