logger.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. import logging
  2. import os
  3. import sys
  4. import traceback
  5. from datetime import datetime
  6. console_formatter = logging.Formatter(
  7. '\033[92m%(asctime)s - %(name)s:%(levelname)s\033[0m: %(filename)s:%(lineno)s - %(message)s',
  8. datefmt='%H:%M:%S',
  9. )
  10. file_formatter = logging.Formatter(
  11. '%(asctime)s - %(name)s:%(levelname)s: %(filename)s:%(lineno)s - %(message)s',
  12. datefmt='%H:%M:%S',
  13. )
  14. llm_formatter = logging.Formatter(
  15. '%(message)s'
  16. )
  17. def get_console_handler():
  18. """
  19. Returns a console handler for logging.
  20. """
  21. console_handler = logging.StreamHandler()
  22. console_handler.setLevel(logging.INFO)
  23. console_handler.setFormatter(console_formatter)
  24. return console_handler
  25. def get_file_handler():
  26. """
  27. Returns a file handler for logging.
  28. """
  29. log_dir = os.path.join(os.getcwd(), 'logs')
  30. os.makedirs(log_dir, exist_ok=True)
  31. timestamp = datetime.now().strftime('%Y-%m-%d_%H-%M-%S')
  32. file_name = f'opendevin_{timestamp}.log'
  33. file_handler = logging.FileHandler(os.path.join(log_dir, file_name))
  34. file_handler.setLevel(logging.DEBUG)
  35. file_handler.setFormatter(file_formatter)
  36. return file_handler
  37. # Set up logging
  38. logging.basicConfig(level=logging.ERROR)
  39. def log_uncaught_exceptions(ex_cls, ex, tb):
  40. """
  41. Logs uncaught exceptions along with the traceback.
  42. Args:
  43. ex_cls (type): The type of the exception.
  44. ex (Exception): The exception instance.
  45. tb (traceback): The traceback object.
  46. Returns:
  47. None
  48. """
  49. logging.error(''.join(traceback.format_tb(tb)))
  50. logging.error('{0}: {1}'.format(ex_cls, ex))
  51. sys.excepthook = log_uncaught_exceptions
  52. opendevin_logger = logging.getLogger('opendevin')
  53. opendevin_logger.setLevel(logging.INFO)
  54. opendevin_logger.addHandler(get_console_handler())
  55. opendevin_logger.addHandler(get_file_handler())
  56. opendevin_logger.propagate = False
  57. opendevin_logger.debug('Logging initialized')
  58. opendevin_logger.debug('Logging to %s', os.path.join(
  59. os.getcwd(), 'logs', 'opendevin.log'))
  60. # Exclude "litellm" from logging output
  61. logging.getLogger('LiteLLM').disabled = True
  62. logging.getLogger('LiteLLM Router').disabled = True
  63. logging.getLogger('LiteLLM Proxy').disabled = True
  64. # LLM prompt and response logging
  65. class LlmFileHandler(logging.FileHandler):
  66. def __init__(self, filename, mode='a', encoding=None, delay=False):
  67. """
  68. Initializes an instance of LlmFileHandler.
  69. Args:
  70. filename (str): The name of the log file.
  71. mode (str, optional): The file mode. Defaults to 'a'.
  72. encoding (str, optional): The file encoding. Defaults to None.
  73. delay (bool, optional): Whether to delay file opening. Defaults to False.
  74. """
  75. self.filename = filename
  76. self.message_counter = 1
  77. self.session = datetime.now().strftime('%y-%m-%d_%H-%M-%S')
  78. self.log_directory = os.path.join(
  79. os.getcwd(), 'logs', 'llm', self.session)
  80. os.makedirs(self.log_directory, exist_ok=True)
  81. self.baseFilename = os.path.join(
  82. self.log_directory, f'{self.filename}_{self.message_counter:03}.log')
  83. super().__init__(self.baseFilename, mode, encoding, delay)
  84. def emit(self, record):
  85. """
  86. Emits a log record.
  87. Args:
  88. record (logging.LogRecord): The log record to emit.
  89. """
  90. self.baseFilename = os.path.join(
  91. self.log_directory, f'{self.filename}_{self.message_counter:03}.log')
  92. self.stream = self._open()
  93. super().emit(record)
  94. self.stream.close
  95. opendevin_logger.debug('Logging to %s', self.baseFilename)
  96. self.message_counter += 1
  97. def get_llm_prompt_file_handler():
  98. """
  99. Returns a file handler for LLM prompt logging.
  100. """
  101. llm_prompt_file_handler = LlmFileHandler('prompt')
  102. llm_prompt_file_handler.setLevel(logging.INFO)
  103. llm_prompt_file_handler.setFormatter(llm_formatter)
  104. return llm_prompt_file_handler
  105. def get_llm_response_file_handler():
  106. """
  107. Returns a file handler for LLM response logging.
  108. """
  109. llm_response_file_handler = LlmFileHandler('response')
  110. llm_response_file_handler.setLevel(logging.INFO)
  111. llm_response_file_handler.setFormatter(llm_formatter)
  112. return llm_response_file_handler
  113. llm_prompt_logger = logging.getLogger('prompt')
  114. llm_prompt_logger.propagate = False
  115. llm_prompt_logger.addHandler(get_llm_prompt_file_handler())
  116. llm_response_logger = logging.getLogger('response')
  117. llm_response_logger.propagate = False
  118. llm_response_logger.addHandler(get_llm_response_file_handler())