Skip to content

Instantly share code, notes, and snippets.

@jbvrtx
Last active June 12, 2023 14:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jbvrtx/f55040cfbf945cc456d4a1b0e00a836d to your computer and use it in GitHub Desktop.
Save jbvrtx/f55040cfbf945cc456d4a1b0e00a836d to your computer and use it in GitHub Desktop.
Statically Create Logs of Completed Tasks in Unity Editor
using Newtonsoft.Json;
using System;
using System.Linq;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
namespace Logging
{
public static class ProgressLogger
{
// Constants
private const string FolderName = "/Logs/";
private const string FileName = "taskLogs.json";
private const string BackupPrefix = "backup_";
// Variables
private static List<TaskLogEntry> _currentTaskLogEntries = new List<TaskLogEntry>();
private static bool initialized = false;
private static bool dirty = false;
// Properties
public static string FolderPath { get => Application.persistentDataPath + FolderName; }
public static string FullPath { get => Application.persistentDataPath + FolderName + FileName; }
public static List<TaskLogEntry> CurrentTaskLogEntries
{
get
{
// Initialize to load logs before allowing access
if (!initialized) Initialize();
return _currentTaskLogEntries;
}
private set
{
if (value != null) _currentTaskLogEntries = value;
}
}
public static void Initialize()
{
if (!initialized)
{
initialized = true;
// Subscribe to event to save logs on exit
Application.quitting += SaveLogsToDisk;
// Load logs on first use
LoadLogs();
}
}
public static void CreateLog(string taskName, int attempts, bool isSuccess, TimeSpan duration)
{
// Create log entry and add it to the list
CurrentTaskLogEntries.Add(new TaskLogEntry(taskName, DateTime.Now, attempts, isSuccess, duration));
dirty = true;
}
public static void SaveLogsToDisk()
{
if (!dirty) return;
// Serialize to JSON
string jsonText = JsonConvert.SerializeObject(CurrentTaskLogEntries, Formatting.Indented);
try
{
// Create folder & write to file
if (!Directory.Exists(FolderPath)) Directory.CreateDirectory(FolderPath);
using (TextWriter textWriter = new StreamWriter(FullPath, false))
{
textWriter.Write(jsonText);
dirty = false;
}
Debug.Log($"{nameof(ExerciseProgressLogger)}: Logs saved successfully at {FullPath}.");
}
catch (IOException exception)
{
Debug.LogError($"{nameof(ExerciseProgressLogger)}: Logs could not be saved. Exception text: " + exception);
throw;
}
}
public static void LoadLogs()
{
// Read file & Parse Json Data
try
{
// Check if file exists
if (!File.Exists(FullPath))
{
DeleteLogHistory();
}
// Read file and parse json content
string jsonText = File.ReadAllText(FullPath);
CurrentTaskLogEntries = JsonConvert.DeserializeObject<List<TaskLogEntry>>(jsonText);
Debug.Log($"{nameof(ExerciseProgressLogger)}: Successfully loaded {CurrentTaskLogEntries.Count} logs.");
}
// Catch errors in the Serialization Process
catch (JsonException)
{
// Create backup of old log file
Debug.LogWarning($"{nameof(ExerciseProgressLogger)}: Log file corrupted, creating backup.");
CreateBackup();
DeleteLogHistory();
}
if (CurrentTaskLogEntries.Count > 0)
TaskLogEntry.CurrentExerciseRunID = CurrentTaskLogEntries.Max(entry => entry.ExerciseRunID);
else
TaskLogEntry.CurrentExerciseRunID = 0;
}
private static void CreateBackup()
{
string backupPath = FolderPath + BackupPrefix + FileName;
if (File.Exists(backupPath)) File.Delete(backupPath);
File.Move(FullPath, backupPath);
Debug.LogWarning($"{nameof(ExerciseProgressLogger)}: Backup created at " + backupPath);
}
public static void DeleteLogHistory()
{
// Saving new empty log file
dirty = true;
SaveLogsToDisk();
TaskLogEntry.CurrentExerciseRunID = 0;
}
}
}
using System;
using UnityEngine;
namespace Logging
{
[System.Serializable]
public class TaskLogEntry
{
// Serialized fields
[SerializeField] private string _taskName;
[SerializeField] private DateTime _creationDate;
[SerializeField] private int _retryNumber;
[SerializeField] private bool _successfulCompletion;
[SerializeField] private TimeSpan _timeSpent;
[SerializeField] private ulong _exerciseRunID; // Used to identify tasks that belong to a consecutive run
// Properties
public string TaskName { get => _taskName; set => _taskName = value; }
public DateTime CreationDate { get => _creationDate; set => _creationDate = value; }
public int RetryNumber { get => _retryNumber; set => _retryNumber = value; }
public bool SuccessfulCompletion { get => _successfulCompletion; set => _successfulCompletion = value; }
public TimeSpan TimeSpent { get => _timeSpent; set => _timeSpent = value; }
public ulong ExerciseRunID { get => _exerciseRunID; set => _exerciseRunID = value; }
public static ulong CurrentExerciseRunID { get; set; } // Global value (current highest id)
// Auto-generated constructor
public TaskLogEntry(string taskName, DateTime creationDate, int retryNumber, bool finalResult, TimeSpan timeSpent)
{
// Assign given values
TaskName = taskName;
CreationDate = creationDate;
RetryNumber = retryNumber;
SuccessfulCompletion = finalResult;
TimeSpent = timeSpent;
_exerciseRunID = CurrentExerciseRunID;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment