Skip to content

Commit a063c60

Browse files
authored
Merge pull request #1745 from AllenNeuralDynamics/feat-lifecycle-logs
Adds lifecycle logger to log start, complete, and failure logs
2 parents e2437f0 + 24be3cc commit a063c60

3 files changed

Lines changed: 49 additions & 3 deletions

File tree

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ dependencies = [
4848
"winkerberos; sys_platform == 'win32'",
4949
"ldap3; sys_platform == 'win32'",
5050
"msal; sys_platform == 'win32'",
51+
"log-schema==0.2.10.dev1"
5152
]
5253

5354
[project.optional-dependencies]

src/foraging_gui/Foraging.py

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
import requests
2929
import serial
3030
import yaml
31+
32+
import log_schema
3133
from aind_auto_train.schema.task import TrainingStage
3234
from aind_behavior_services.session import AindBehaviorSessionModel
3335
from aind_data_schema.core.session import Session
@@ -351,6 +353,9 @@ def __init__(self, parent=None, box_number=1, start_bonsai_ide=True):
351353

352354
# load the rig metadata
353355
self._load_rig_metadata()
356+
357+
# setup life-cycle logger
358+
self.lifecycle_logger = self.setup_lifecycle_logger()
354359

355360
# Initializes session log handler as None
356361
self.session_log_handler = None
@@ -365,6 +370,27 @@ def __init__(self, parent=None, box_number=1, start_bonsai_ide=True):
365370
self._ReconnectBonsai()
366371
logging.info("Start up complete")
367372

373+
def setup_lifecycle_logger(self) -> logging.Logger:
374+
375+
"""
376+
Creates logger for start, stop, and failure events with formatter adhering to aind log standards.
377+
"""
378+
379+
# Ensure the directory exists
380+
os.makedirs(Path(self.Settings["lifecycle_log_dir"]), exist_ok=True)
381+
382+
lifecycle_logger = logging.getLogger("lifecycle")
383+
lifecycle_logger.setLevel(logging.INFO)
384+
385+
timestamp = datetime.now().strftime("%Y%m%dT%H%M%SZ")
386+
filename = f"lifecycle_log_{timestamp}.jsonl"
387+
file_handler = logging.FileHandler(os.path.join(self.Settings["lifecycle_log_dir"], filename), encoding="utf-8")
388+
file_handler.setLevel(logging.INFO)
389+
file_handler.setFormatter(log_schema.DefaultFormatter())
390+
lifecycle_logger.addHandler(file_handler)
391+
392+
return lifecycle_logger
393+
368394
def _load_rig_metadata(self):
369395
"""Load the latest rig metadata"""
370396

@@ -1594,6 +1620,7 @@ def _restartlogging(self, log_folder=None,start_from_camera=False):
15941620
self.Save.setStyleSheet(
15951621
"color: white;background-color : mediumorchid"
15961622
)
1623+
15971624
else:
15981625
# temporary logging
15991626
loggingtype = 1
@@ -1961,6 +1988,11 @@ def _GetSettings(self):
19611988
"aind_watchdog_service",
19621989
"manifest",
19631990
),
1991+
"lifecycle_log_dir": os.path.join(
1992+
os.path.expanduser("~"),
1993+
"Documents",
1994+
"lifecycle_logs",
1995+
),
19641996
"transfer_service_job_type": "dynamic_foraging_compression",
19651997
"auto_engage": True,
19661998
"clear_figure_after_save": True,
@@ -3937,7 +3969,7 @@ def _Save(self, ForceSave=0, SaveAs=0, SaveContinue=0, BackupSave=0):
39373969
if self.CreateNewFolder == 1:
39383970
self._GetSaveFolder()
39393971
self.CreateNewFolder = 0
3940-
3972+
39413973
if not os.path.exists(os.path.dirname(self.SaveFileJson)):
39423974
os.makedirs(os.path.dirname(self.SaveFileJson))
39433975
logging.info(
@@ -4225,6 +4257,12 @@ def _Save(self, ForceSave=0, SaveAs=0, SaveContinue=0, BackupSave=0):
42254257
elif session is None:
42264258
logging.warning(f"Waterlog for mouse {self.behavior_session_model.subject} cannot be added to slims"
42274259
f" due do metadata generation failure.")
4260+
4261+
# add complete log to lifecycle
4262+
self.lifecycle_logger.info("Session ended.", extra={"subject_id": self.behavior_session_model.subject,
4263+
"acquisition_name": self.behavior_session_model.session_name,
4264+
"event_type": "stage_complete"})
4265+
42284266
except Exception as e:
42294267
logging.warning(
42304268
"Meta data is not saved!",
@@ -6186,6 +6224,10 @@ def _Start(self):
61866224
# Start logging if the formal logging is not started
61876225
if self.logging_type != 0:
61886226
self.Ot_log_folder = self._restartlogging()
6227+
# Need to log start event after session_name has been set in_restartlogging
6228+
self.lifecycle_logger.info("Session started.", extra={"subject_id": self.behavior_session_model.subject,
6229+
"acquisition_name": self.behavior_session_model.session_name,
6230+
"event_type": "stage_start"})
61896231
except Exception as e:
61906232
if "ConnectionAbortedError" in str(e):
61916233
logging.info("lost bonsai connection: restartlogging()")
@@ -6641,6 +6683,9 @@ def _StartTrialLoop(self, GeneratedTrials, worker1, worker_save):
66416683
self.ANewTrial = 1
66426684
self.Start.setChecked(False)
66436685
self.Start.setStyleSheet("background-color : none")
6686+
self.lifecycle_logger.info("Session failed.", extra={"subject_id": self.behavior_session_model.subject,
6687+
"acquisition_name": self.behavior_session_model.session_name,
6688+
"event_type": "stage_failure"})
66446689
break
66456690
# receive licks and update figures
66466691
if self.actionDrawing_after_stopping.isChecked() == False:
@@ -7432,7 +7477,6 @@ def setup_loki_logging(box_number):
74327477
handler.setLevel(logging.INFO)
74337478
logger.root.addHandler(handler)
74347479

7435-
74367480
def start_gui_log_file(box_number):
74377481
"""
74387482
Starts a log file for the gui.

src/foraging_gui/settings_model.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from typing import Literal, Optional
22

33
from pydantic import BaseModel, Field
4-
4+
from pathlib import Path
55

66
class BonsaiSettingsModel(BaseModel):
77
"""
@@ -182,6 +182,7 @@ class DFTSettingsModel(BaseModel):
182182
save_each_trial: bool
183183
AutomaticUpload: bool
184184
manifest_flag_dir: str
185+
lifecycle_log_dir: Path
185186
transfer_service_job_type: str
186187
auto_engage: bool
187188
clear_figure_after_save: bool

0 commit comments

Comments
 (0)