// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. // If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. // Copyright (C) LibreHardwareMonitor and Contributors. // Partial Copyright (C) Michael Möller and Contributors. // All Rights Reserved. using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; using LibreHardwareMonitor.Hardware; namespace LibreHardwareMonitor.Utilities; public class Logger { private const string FileNameFormat = "LibreHardwareMonitorLog-{0:yyyy-MM-dd}{1}.csv"; private readonly IComputer _computer; private DateTime _day = DateTime.MinValue; private string _fileName; private string[] _identifiers; private ISensor[] _sensors; private DateTime _lastLoggedTime = DateTime.MinValue; public LoggerFileRotation FileRotationMethod = LoggerFileRotation.PerSession; public Logger(IComputer computer) { _computer = computer; _computer.HardwareAdded += HardwareAdded; _computer.HardwareRemoved += HardwareRemoved; } private void HardwareRemoved(IHardware hardware) { hardware.SensorAdded -= SensorAdded; hardware.SensorRemoved -= SensorRemoved; foreach (ISensor sensor in hardware.Sensors) SensorRemoved(sensor); foreach (IHardware subHardware in hardware.SubHardware) HardwareRemoved(subHardware); } private void HardwareAdded(IHardware hardware) { foreach (ISensor sensor in hardware.Sensors) SensorAdded(sensor); hardware.SensorAdded += SensorAdded; hardware.SensorRemoved += SensorRemoved; foreach (IHardware subHardware in hardware.SubHardware) HardwareAdded(subHardware); } private void SensorAdded(ISensor sensor) { if (_sensors == null) return; for (int i = 0; i < _sensors.Length; i++) { if (sensor.Identifier.ToString() == _identifiers[i]) _sensors[i] = sensor; } } private void SensorRemoved(ISensor sensor) { if (_sensors == null) return; for (int i = 0; i < _sensors.Length; i++) { if (sensor == _sensors[i]) _sensors[i] = null; } } private static string GetFileName(DateTime date, uint sessionNumber = 0) { return AppDomain.CurrentDomain.BaseDirectory + Path.DirectorySeparatorChar + string.Format(FileNameFormat, date, sessionNumber == 0 ? "" : "-" + sessionNumber); } private bool OpenExistingLogFile() { if (!File.Exists(_fileName)) return false; try { string line; using (StreamReader reader = new StreamReader(_fileName)) line = reader.ReadLine(); if (string.IsNullOrEmpty(line)) return false; _identifiers = line.Split(',').Skip(1).ToArray(); } catch { _identifiers = null; return false; } if (_identifiers.Length == 0) { _identifiers = null; return false; } _sensors = new ISensor[_identifiers.Length]; SensorVisitor visitor = new SensorVisitor(sensor => { for (int i = 0; i < _identifiers.Length; i++) if (sensor.Identifier.ToString() == _identifiers[i]) _sensors[i] = sensor; }); visitor.VisitComputer(_computer); return true; } private void CreateNewLogFile() { IList list = new List(); SensorVisitor visitor = new SensorVisitor(sensor => { list.Add(sensor); }); visitor.VisitComputer(_computer); _sensors = list.ToArray(); _identifiers = _sensors.Select(s => s.Identifier.ToString()).ToArray(); using (StreamWriter writer = new StreamWriter(_fileName, false)) { writer.Write(","); for (int i = 0; i < _sensors.Length; i++) { writer.Write(_sensors[i].Identifier); if (i < _sensors.Length - 1) writer.Write(","); else writer.WriteLine(); } writer.Write("Time,"); for (int i = 0; i < _sensors.Length; i++) { writer.Write('"'); writer.Write(_sensors[i].Name); writer.Write('"'); if (i < _sensors.Length - 1) writer.Write(","); else writer.WriteLine(); } } } public TimeSpan LoggingInterval { get; set; } public void Log() { DateTime now = DateTime.Now; if (_lastLoggedTime + LoggingInterval - new TimeSpan(5000000) > now) return; switch (FileRotationMethod) { case LoggerFileRotation.PerSession: // Create file if it does not exist or the logging interval has passed (+ some margin) if (!File.Exists(_fileName) || now - _lastLoggedTime > (LoggingInterval + TimeSpan.FromMilliseconds(100))) { uint sessionNumber = 1; do { _fileName = GetFileName(DateTime.Now, sessionNumber); sessionNumber++; } while (File.Exists(_fileName)); CreateNewLogFile(); } break; case LoggerFileRotation.Daily: // Create a new file if the day has changed or the file does not exist if (_day != now.Date || !File.Exists(_fileName)) { _day = now.Date; _fileName = GetFileName(_day); if (!OpenExistingLogFile()) CreateNewLogFile(); } break; } try { using (StreamWriter writer = new StreamWriter(new FileStream(_fileName, FileMode.Append, FileAccess.Write, FileShare.ReadWrite))) { writer.Write(now.ToString("G", CultureInfo.InvariantCulture)); writer.Write(","); for (int i = 0; i < _sensors.Length; i++) { if (_sensors[i] != null) { float? value = _sensors[i].Value; if (value.HasValue) writer.Write(value.Value.ToString("R", CultureInfo.InvariantCulture)); } if (i < _sensors.Length - 1) writer.Write(","); else writer.WriteLine(); } } } catch (IOException) { } _lastLoggedTime = now; } }