Log gaze analysis ================= [ArFrame](../../argaze.md/#argaze.ArFeatures.ArFrame) and [ArLayer](../../argaze.md/#argaze.ArFeatures.ArLayer) analysis can be logged by registering observers to their **look** method. ## Enable ArFrame and ArLayer analysis logging [ArFrame](../../argaze.md/#argaze.ArFeatures.ArFrame) and [ArLayer](../../argaze.md/#argaze.ArFeatures.ArLayer) have an observers attribute to enable pipeline execution logging. Here is an extract from the JSON ArFrame configuration file where logging is enabled for the [ArFrame](../../argaze.md/#argaze.ArFeatures.ArFrame) and for one [ArLayer](../../argaze.md/#argaze.ArFeatures.ArLayer) by pointing to dedicated Python files: ```json { "name": "My FullHD screen", "size": [1920, 1080], "observers": "my_frame_logger.py", ... "layers": { "MyLayer": { "observers": "my_layer_logger.py", ... } } } ``` !!! note [ArFrame](../../argaze.md/#argaze.ArFeatures.ArFrame) and its [ArLayers](../../argaze.md/#argaze.ArFeatures.ArLayer) automatically notify **look** method observers after each call. Here is *my_frame_logger.py* file: ```python from argaze import DataFeatures from argaze.utils import UtilsFeatures class ScanPathAnalysisLogger(DataFeatures.PipelineStepObserver, UtilsFeatures.FileWriter): def on_look(self, timestamp, frame): """Log scan path metrics""" if frame.analysis_available: log = ( timestamp, frame.scan_path_analyzers['argaze.GazeAnalysis.Basic'].path_duration, frame.scan_path_analyzers['argaze.GazeAnalysis.Basic'].steps_number ) # Write to file self.write(log) # Export logger as observer __observers__ = { "Scan path analysis logger": ScanPathAnalysisLogger(path="./scan_path_metrics.csv", header="Timestamp (ms), Duration (ms), Steps number") } ``` Assuming that [ArGaze.GazeAnalysis.Basic](../../argaze.md/#argaze.GazeAnalysis.Basic) scan path analysis module is enabled for 'My FullHD screen' ArFrame, a ***scan_path_metrics.csv*** file would be created: |Timestamp (ms)|Duration (ms)|Steps number| |:-------------|:------------|:-----------| |3460 |1750 |2 | |4291 |2623 |3 | |4769 |3107 |4 | |6077 |4411 |5 | |6433 |4760 |6 | |7719 |6050 |7 | |... |... |... | Here is *my_layer_logger.py* file: ```python from argaze import DataFeatures from argaze.utils import UtilsFeatures class AOIScanPathAnalysisLogger(DataFeatures.PipelineStepObserver, UtilsFeatures.FileWriter): def on_look(self, timestamp, layer): """Log aoi scan path metrics""" if layer.analysis_available: log = ( timestamp, layer.aoi_scan_path_analyzers['argaze.GazeAnalysis.NGram'].ngrams_count ) # Write to file self.write(log) # Export logger as observer __observers__ = { "AOI Scan path analysis logger": AOIScanPathAnalysisLogger(path="./aoi_scan_path_metrics.csv", header="Timestamp (ms), NGram counts") } ``` Assuming that [ArGaze.GazeAnalysis.NGram](../../argaze.md/#argaze.GazeAnalysis.NGram) AOI scan path analysis module is enabled for 'MyLayer' ArLayer, a ***aoi_scan_path_metrics.csv*** file would be created: |Timestamp (ms)|NGram counts| |:-------------|:-----------| |5687 |"{3: {}, 4: {}, 5: {}}"| |6208 |"{3: {('LeftPanel', 'GeoSector', 'CircularWidget'): 1}, 4: {}, 5: {}}"| |... |... |