Skip to content

Commit ebde196

Browse files
lalosonichi
andauthored
feat: add event logging api and more tracing (#2478)
* feat: add event logging api and more tracing * code fmt shenanigans * fixup * Update test_agent_logging.py * Update test_agent_logging.py * Update test_agent_logging.py * Update sqlite_logger.py * Update test_agent_logging.py * Update sqlite_logger.py --------- Co-authored-by: Chi Wang <[email protected]>
1 parent a41182a commit ebde196

File tree

6 files changed

+97
-5
lines changed

6 files changed

+97
-5
lines changed

autogen/agentchat/conversable_agent.py

+13-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
from ..function_utils import get_function_schema, load_basemodels_if_needed, serialize_to_str
3333
from ..io.base import IOStream
3434
from ..oai.client import ModelClient, OpenAIWrapper
35-
from ..runtime_logging import log_new_agent, logging_enabled
35+
from ..runtime_logging import log_event, log_new_agent, logging_enabled
3636
from .agent import Agent, LLMAgent
3737
from .chat import ChatResult, a_initiate_chats, initiate_chats
3838
from .utils import consolidate_chat_info, gather_usage_summary
@@ -757,6 +757,9 @@ def _print_received_message(self, message: Union[Dict, str], sender: Agent):
757757
def _process_received_message(self, message: Union[Dict, str], sender: Agent, silent: bool):
758758
# When the agent receives a message, the role of the message is "user". (If 'role' exists and is 'function', it will remain unchanged.)
759759
valid = self._append_oai_message(message, "user", sender)
760+
if logging_enabled():
761+
log_event(self, "received_message", message=message, sender=sender.name, valid=valid)
762+
760763
if not valid:
761764
raise ValueError(
762765
"Received message can't be converted into a valid ChatCompletion message. Either content or function_call must be provided."
@@ -1939,6 +1942,15 @@ def generate_reply(
19391942
continue
19401943
if self._match_trigger(reply_func_tuple["trigger"], sender):
19411944
final, reply = reply_func(self, messages=messages, sender=sender, config=reply_func_tuple["config"])
1945+
if logging_enabled():
1946+
log_event(
1947+
self,
1948+
"reply_func_executed",
1949+
reply_func_module=reply_func.__module__,
1950+
reply_func_name=reply_func.__name__,
1951+
final=final,
1952+
reply=reply,
1953+
)
19421954
if final:
19431955
return reply
19441956
return self._default_auto_reply

autogen/logger/base_logger.py

+13-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from openai.types.chat import ChatCompletion
1010

1111
if TYPE_CHECKING:
12-
from autogen import ConversableAgent, OpenAIWrapper
12+
from autogen import Agent, ConversableAgent, OpenAIWrapper
1313

1414
ConfigItem = Dict[str, Union[str, List[str]]]
1515
LLMConfig = Dict[str, Union[None, float, int, ConfigItem, List[ConfigItem]]]
@@ -68,6 +68,18 @@ def log_new_agent(self, agent: ConversableAgent, init_args: Dict[str, Any]) -> N
6868
"""
6969
...
7070

71+
@abstractmethod
72+
def log_event(self, source: Union[str, Agent], name: str, **kwargs: Dict[str, Any]) -> None:
73+
"""
74+
Log an event for an agent.
75+
76+
Args:
77+
source (str or Agent): The source/creator of the event as a string name or an Agent instance
78+
name (str): The name of the event
79+
kwargs (dict): The event information to log
80+
"""
81+
...
82+
7183
@abstractmethod
7284
def log_new_wrapper(self, wrapper: OpenAIWrapper, init_args: Dict[str, Union[LLMConfig, List[LLMConfig]]]) -> None:
7385
"""

autogen/logger/sqlite_logger.py

+50-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
from .base_logger import LLMConfig
1818

1919
if TYPE_CHECKING:
20-
from autogen import ConversableAgent, OpenAIWrapper
20+
from autogen import Agent, ConversableAgent, OpenAIWrapper
2121

2222
logger = logging.getLogger(__name__)
2323
lock = threading.Lock()
@@ -103,6 +103,20 @@ class TEXT, -- type or class name of cli
103103
"""
104104
self._run_query(query=query)
105105

106+
query = """
107+
CREATE TABLE IF NOT EXISTS events (
108+
event_name TEXT,
109+
source_id INTEGER,
110+
source_name TEXT,
111+
agent_module TEXT DEFAULT NULL,
112+
agent_class_name TEXT DEFAULT NULL,
113+
id INTEGER PRIMARY KEY,
114+
json_state TEXT,
115+
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP
116+
);
117+
"""
118+
self._run_query(query=query)
119+
106120
current_verion = self._get_current_db_version()
107121
if current_verion is None:
108122
self._run_query(
@@ -246,6 +260,41 @@ class = excluded.class,
246260
)
247261
self._run_query(query=query, args=args)
248262

263+
def log_event(self, source: Union[str, Agent], name: str, **kwargs: Dict[str, Any]) -> None:
264+
from autogen import Agent
265+
266+
if self.con is None:
267+
return
268+
269+
json_args = json.dumps(kwargs, default=lambda o: f"<<non-serializable: {type(o).__qualname__}>>")
270+
271+
if isinstance(source, Agent):
272+
query = """
273+
INSERT INTO events (source_id, source_name, event_name, agent_module, agent_class_name, json_state, timestamp) VALUES (?, ?, ?, ?, ?, ?, ?)
274+
"""
275+
args = (
276+
id(source),
277+
source.name if hasattr(source, "name") else source,
278+
name,
279+
source.__module__,
280+
source.__class__.__name__,
281+
json_args,
282+
get_current_ts(),
283+
)
284+
self._run_query(query=query, args=args)
285+
else:
286+
query = """
287+
INSERT INTO events (source_id, source_name, event_name, json_state, timestamp) VALUES (?, ?, ?, ?, ?)
288+
"""
289+
args_str_based = (
290+
id(source),
291+
source.name if hasattr(source, "name") else source,
292+
name,
293+
json_args,
294+
get_current_ts(),
295+
)
296+
self._run_query(query=query, args=args_str_based)
297+
249298
def log_new_wrapper(self, wrapper: OpenAIWrapper, init_args: Dict[str, Union[LLMConfig, List[LLMConfig]]]) -> None:
250299
if self.con is None:
251300
return

autogen/runtime_logging.py

+9-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from autogen.logger.logger_factory import LoggerFactory
1313

1414
if TYPE_CHECKING:
15-
from autogen import ConversableAgent, OpenAIWrapper
15+
from autogen import Agent, ConversableAgent, OpenAIWrapper
1616

1717
logger = logging.getLogger(__name__)
1818

@@ -62,6 +62,14 @@ def log_new_agent(agent: ConversableAgent, init_args: Dict[str, Any]) -> None:
6262
autogen_logger.log_new_agent(agent, init_args)
6363

6464

65+
def log_event(source: Union[str, Agent], name: str, **kwargs: Dict[str, Any]) -> None:
66+
if autogen_logger is None:
67+
logger.error("[runtime logging] log_event: autogen logger is None")
68+
return
69+
70+
autogen_logger.log_event(source, name, **kwargs)
71+
72+
6573
def log_new_wrapper(wrapper: OpenAIWrapper, init_args: Dict[str, Union[LLMConfig, List[LLMConfig]]]) -> None:
6674
if autogen_logger is None:
6775
logger.error("[runtime logging] log_new_wrapper: autogen logger is None")

samples/tools/autogenbench/autogenbench/template/testbed_utils.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ def init():
7070

7171
# Start logging
7272
if LOGGING_ENABLED:
73-
autogen.runtime_logging.start(config={"dbname": "telemetry.db"})
73+
autogen.runtime_logging.start(config={"dbname": "telemetry.sqlite"})
7474

7575

7676
def finalize(agents):

test/agentchat/test_agent_logging.py

+11
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@
3434

3535
OAI_WRAPPERS_QUERY = "SELECT id, wrapper_id, session_id, init_args, timestamp FROM oai_wrappers"
3636

37+
EVENTS_QUERY = (
38+
"SELECT source_id, source_name, event_name, agent_module, agent_class_name, json_state, timestamp FROM events"
39+
)
3740

3841
if not skip_openai:
3942
config_list = autogen.config_list_from_json(
@@ -242,6 +245,14 @@ def test_groupchat_logging(db_connection):
242245
rows = cur.fetchall()
243246
assert len(rows) == 3
244247

248+
# Verify events
249+
cur.execute(EVENTS_QUERY)
250+
rows = cur.fetchall()
251+
json_state = json.loads(rows[0]["json_state"])
252+
assert rows[0]["event_name"] == "received_message"
253+
assert json_state["message"] == "Can you explain the difference between eigenvalues and singular values again?"
254+
assert len(rows) == 15
255+
245256
# Verify schema version
246257
version_query = "SELECT id, version_number from version"
247258
cur.execute(version_query)

0 commit comments

Comments
 (0)