/// Copyright 2016 Kopano b.v. /// /// This program is free software: you can redistribute it and/or modify /// it under the terms of the GNU Affero General Public License, version 3, /// as published by the Free Software Foundation. /// /// This program is distributed in the hope that it will be useful, /// but WITHOUT ANY WARRANTY; without even the implied warranty of /// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the /// GNU Affero General Public License for more details. /// /// You should have received a copy of the GNU Affero General Public License /// along with this program.If not, see. /// /// Consult LICENSE file for details using Acacia.Utils; using Acacia.ZPush; using Microsoft.Office.Core; using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Globalization; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Acacia.Features.DebugSupport { public enum DebugCategory { Version, Memory, Wrappers, Misc, System, Accounts, Features, AddIns } public class DebugCategoryAttribute : CategoryAttribute { // Add tabs; these are not printed, but are used for the sorting public DebugCategoryAttribute(DebugCategory order) : base(order.ToString().PadLeft(typeof(DebugCategory).GetEnumNames().Length - (int)order + order.ToString().Length, '\t')) { } } public class DebugInfoConverter : ExpandableObjectConverter { private class CustomPropertyDescriptor : PropertyDescriptor { private readonly TProperty value; public CustomPropertyDescriptor(string propertyName, DebugCategory category, TProperty value) : base(propertyName, new Attribute[] { new DebugCategoryAttribute(category) }) { this.value = value; } public override bool CanResetValue(object component) { return false; } public override Type ComponentType { get { return typeof(TComponent); } } public override object GetValue(object component) { return value; } public override bool IsReadOnly { get { return true; } } public override Type PropertyType { get { return typeof(TProperty); } } public override void ResetValue(object component) { SetValue(component, null); } public override void SetValue(object component, object value) { } public override bool ShouldSerializeValue(object component) { return false; } } public override bool GetPropertiesSupported(ITypeDescriptorContext context) { return true; } public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes) { PropertyDescriptorCollection properties = new PropertyDescriptorCollection(base.GetProperties(context, value, attributes).Cast().ToArray()); DebugInfo info = value as DebugInfo; if (info != null) { // Add accounts foreach (ZPushAccount account in ThisAddIn.Instance.Watcher.Accounts.GetAccounts()) { PropertyDescriptor p = new CustomPropertyDescriptor(account.DisplayName, DebugCategory.Accounts, account); properties.Add(p); } // Add Features foreach (Feature feature in ThisAddIn.Instance.Features) { PropertyDescriptor p = new CustomPropertyDescriptor(feature.Name, DebugCategory.Features, feature); properties.Add(p); } // Add Add-ins foreach (COMAddIn addin in ThisAddIn.Instance.Application.COMAddIns) { PropertyDescriptor p = new CustomPropertyDescriptor(addin.ProgId, DebugCategory.AddIns, addin.Description); properties.Add(p); } } return properties; } } [TypeConverter(typeof(DebugInfoConverter))] class DebugInfo { #region Version [DebugCategory(DebugCategory.Version)] public string Version { get { return BuildVersions.VERSION; } } [DebugCategory(DebugCategory.Version)] public string Revision { get { return BuildVersions.REVISION; } } [DebugCategory(DebugCategory.Version)] public string BuildDate { get { return LibUtils.BuildTime.ToString(); } } #endregion #region Memory [DebugCategory(DebugCategory.Memory)] public string TotalMemory { get { return MemoryToString(GC.GetTotalMemory(false)); } } #endregion #region Wrappers [DebugCategory(DebugCategory.Wrappers)] public long ActiveWrappers { get { return Statistics.CreatedWrappers - Statistics.DeletedWrappers; } } [DebugCategory(DebugCategory.Wrappers)] public long CreatedWrappers { get { return Statistics.CreatedWrappers; } } [DebugCategory(DebugCategory.Wrappers)] public long DeletedWrappers { get { return Statistics.DeletedWrappers; } } [DebugCategory(DebugCategory.Wrappers)] public long DisposedWrappers { get { return Statistics.DisposedWrappers; } } [DebugCategory(DebugCategory.Wrappers)] public long UndisposedWrappers { get { return Statistics.DeletedWrappers - Statistics.DisposedWrappers; } } #endregion #region Misc [DebugCategory(DebugCategory.Misc)] public string StartupTime { get { return TimeToString(Statistics.StartupTime); } } [DebugCategory(DebugCategory.Misc)] public LogLevel LogLevel { get { return Logger.Instance.MinLevel; } set { Logger.Instance.SetLevel(value); } } [DebugCategory(DebugCategory.Misc)] public string Threading { get { return Tasks.Executor.Name; } } [DebugCategory(DebugCategory.Misc)] public bool ZPushSync { get { return ThisAddIn.Instance.Watcher.Sync.Enabled; } } [DebugCategory(DebugCategory.Misc)] public TimeSpan ZPushSyncPeriod { get { return ThisAddIn.Instance.Watcher.Sync.Period; } } [DebugCategory(DebugCategory.Misc)] public string Build { get { #if DEBUG return "Debug"; #else return "Release"; #endif } } #endregion #region System [DebugCategory(DebugCategory.System)] public string Locale { get { return CultureInfo.CurrentUICulture.DisplayName; } } [DebugCategory(DebugCategory.System)] public string WindowsVersion { get { return Environment.OSVersion.Version.ToString(); } } [DebugCategory(DebugCategory.System)] public string Architecture { get { return Environment.Is64BitOperatingSystem ? "64 bit" : "32 bit"; } } #endregion #region Outlook [DebugCategory(DebugCategory.System)] public string OutlookVersion { get { return ThisAddIn.Instance.Application.Version; } } [DebugCategory(DebugCategory.System)] public string OutlookArchitecture { get { return Environment.Is64BitProcess ? "64 bit" : "32 bit"; } } #endregion #region Helpers private string TimeToString(Stopwatch time) { return time.ElapsedMilliseconds.ToString("#### ms"); } private static readonly string[] SizeSuffixes = { "bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" }; private string MemoryToString(long value) { if (value < 0) { return "-" + MemoryToString(-value); } int i = 0; decimal dValue = (decimal)value; while (Math.Round(dValue / 1024) >= 1) { dValue /= 1024; i++; } return string.Format("{0:n1} {1}", dValue, SizeSuffixes[i]); } #endregion } }