using UnityEngine; using System.IO; using System.Text; #if UNITY_EDITOR using UnityEditor; #endif namespace SchoenLogger { public class Logger : MonoBehaviour, ILogger where TLogEntry : LogEntry, new() where TCondition : Condition , new() { [Header("General Settings")] public StudyManager studyManager; [Tooltip("Keep empty to autofill to PersistentDataPath")] public string LogPathOverride= ""; [Tooltip("Buffersize (in bytes) for the LogFileWriter. Larger means less writing cycles")] public int BufferSize = 65536; private string LogPath = ""; private string LogFilePath = ""; private string LogFileName = ""; private FileStream LogFileStream; private StreamWriter LogFileWriter; private string CurrentConditionString = ""; private int CurrentParticipantId = -1; // Start is called before the first frame update void Start() { StartLogFileStream(); if (studyManager == null) { studyManager.GetComponent>(); if (studyManager == null) { Debug.LogErrorFormat("{0} has not set studyManager", this.gameObject.name); return; } } studyManager.ChangeCondition.AddListener(OnConditionChanged); } private void OnConditionChanged(TCondition cond, int partId) { CurrentConditionString = cond.ToCsv(); CurrentParticipantId = partId; } private void OnApplicationQuit() { LogFileStream.Flush(); LogFileWriter?.Dispose(); LogFileStream?.Dispose(); Debug.Log("Closed Logger FileStreams!"); } protected void StartLogFileStream() { if(LogPathOverride == "") LogPath = Application.persistentDataPath; else LogPath = LogPathOverride; LogFileName = "log_" + typeof(TLogEntry).Name + ".csv"; LogFilePath = Path.Combine(LogPath, LogFileName); if (!File.Exists(LogFilePath)) { using (FileStream stream = File.Open(LogFilePath, FileMode.Create)) { using (StreamWriter writer = new StreamWriter(stream)) { writer.WriteLine(GetLogFileHeader()); writer.Flush(); } } Debug.LogFormat("Created new Logfile {0}", LogFileName); } LogFileStream = File.Open(LogFilePath, FileMode.Append); LogFileWriter = new StreamWriter(LogFileStream, Encoding.UTF8, BufferSize); LogFileWriter.AutoFlush = true; } protected string GetLogFileHeader() { StringBuilder header = new StringBuilder("ParticipantID"); header.Append(Condition.GetCsvHeader()); header.Append(LogEntry.GetCsvHeader()); return header.ToString(); } public void Log(TLogEntry entry) { string logEntry = CreateLogEntryCsvLine(entry); LogFileWriter.WriteLine(CreateLogEntryCsvLine(entry)); Debug.Log(logEntry); } private string CreateLogEntryCsvLine(TLogEntry entry) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append(CurrentParticipantId); stringBuilder.Append(CurrentConditionString); stringBuilder.Append(entry.ToCsv()); return stringBuilder.ToString(); } public string GetLogPath() { if (LogPath == "") return Application.persistentDataPath; return LogPath; } } public interface ILogger { string GetLogPath(); } #if UNITY_EDITOR [CustomEditor(typeof(Logger<,>), true)] public class LoggerEditor : Editor { public override void OnInspectorGUI() { DrawDefaultInspector(); ILogger Target = (ILogger)target; EditorGUILayout.Space(10); EditorGUILayout.LabelField("Info", EditorStyles.boldLabel); EditorGUILayout.LabelField("Log Path: ", Target.GetLogPath()); if (GUILayout.Button("Show in Explorer")) { string itemPath = Target.GetLogPath().Replace(@"/", @"\"); System.Diagnostics.Process.Start("explorer.exe", "/select,"+itemPath); } } } #endif }