Skip to content

Commit

Permalink
CrashDumper: Allow app configuration of dump directory
Browse files Browse the repository at this point in the history
For detailed information, see 'docs/dev-crashdumpconfig'.

Add a config section to specify the dump path, and clean up parameters before creating a new dump.

  <configSections>
    <sectionGroup name="CrashReporter">
      <section name="CrashDumper" type="RJCP.Diagnostics.Config.CrashDumper, RJCP.Diagnostics.CrashReporter"/>
    </sectionGroup>
  </configSections>

  <CrashReporter>
    <CrashDumper>
      <DumpDirectory path="${LOCALAPPDIR}/CrashDumps" ageDays="45" maxLogs="40"
        freeGb="5" freePercent="1" maxGb="1" minLogs="5"/>
    </CrashDumper>
  </CrashReporter>

Issue: HELIOS-1347
  • Loading branch information
jcurl committed Feb 1, 2020
1 parent a399a93 commit 01f5ac3
Show file tree
Hide file tree
Showing 28 changed files with 737 additions and 25 deletions.
5 changes: 5 additions & 0 deletions CrashReportApp/App.net40.config
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<configuration>
<configSections>
<sectionGroup name="CrashReporter">
<section name="CrashDumper" type="RJCP.Diagnostics.Config.CrashDumper, RJCP.Diagnostics.CrashReporter"/>
<section name="XmlCrashDumper" type="RJCP.Diagnostics.Config.XmlCrashDumper, RJCP.Diagnostics.CrashReporter"/>
<section name="Watchdog" type="RJCP.Diagnostics.Config.Watchdog, RJCP.Diagnostics.CrashReporter"/>
</sectionGroup>
Expand All @@ -12,6 +13,10 @@
</startup>

<CrashReporter>
<CrashDumper>
<DumpDirectory path="${CWD}/CrashDumps"
ageDays="45" maxLogs="40" freeGb="5" freePercent="1" maxGb="1" minLogs="5"/>
</CrashDumper>
<XmlCrashDumper>
<StyleSheet name="RJCP.Diagnostics.CrashReporter, RJCP.Diagnostics.CrashExport.Xml.CrashDump.xsl"/>
</XmlCrashDumper>
Expand Down
5 changes: 5 additions & 0 deletions CrashReportApp/App.net45.config
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<configuration>
<configSections>
<sectionGroup name="CrashReporter">
<section name="CrashDumper" type="RJCP.Diagnostics.Config.CrashDumper, RJCP.Diagnostics.CrashReporter"/>
<section name="XmlCrashDumper" type="RJCP.Diagnostics.Config.XmlCrashDumper, RJCP.Diagnostics.CrashReporter"/>
<section name="Watchdog" type="RJCP.Diagnostics.Config.Watchdog, RJCP.Diagnostics.CrashReporter"/>
</sectionGroup>
Expand All @@ -12,6 +13,10 @@
</startup>

<CrashReporter>
<CrashDumper>
<DumpDirectory path="${CWD}/CrashDumps"
ageDays="45" maxLogs="40" freeGb="5" freePercent="1" maxGb="1" minLogs="5"/>
</CrashDumper>
<XmlCrashDumper>
<StyleSheet name="RJCP.Diagnostics.CrashReporter, RJCP.Diagnostics.CrashExport.Xml.CrashDump.xsl"/>
</XmlCrashDumper>
Expand Down
13 changes: 13 additions & 0 deletions CrashReporter/Config/CrashDumper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace RJCP.Diagnostics.Config
{
using System.Configuration;

internal class CrashDumper : ConfigurationSection
{
[ConfigurationProperty("DumpDirectory", IsRequired = false)]
public DumpDirElement DumpDir
{
get { return (DumpDirElement)this["DumpDirectory"]; }
}
}
}
10 changes: 10 additions & 0 deletions CrashReporter/Config/CrashReporter/CrashConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ internal CrashConfig()
case "Watchdog":
Watchdog = new WatchdogConfig((Watchdog)grp.Sections["Watchdog"]);
break;
case "CrashDumper":
CrashDumper = new CrashDumperConfig((CrashDumper)grp.Sections["CrashDumper"]);
break;
}
} catch (ConfigurationException) {
// Ignore exception errors. They'll be logged by default in the FirstChance.
Expand All @@ -49,6 +52,7 @@ internal CrashConfig()
// making it safer.
if (XmlCrashDumper == null) XmlCrashDumper = new XmlCrashDumperConfig();
if (Watchdog == null) Watchdog = new WatchdogConfig();
if (CrashDumper == null) CrashDumper = new CrashDumperConfig();
}

/// <summary>
Expand All @@ -62,5 +66,11 @@ internal CrashConfig()
/// </summary>
/// <value>The watchdog configuration.</value>
public WatchdogConfig Watchdog { get; private set; }

/// <summary>
/// Gets the crash dumper configuration.
/// </summary>
/// <value>The crash dumper configuration.</value>
public CrashDumperConfig CrashDumper { get; private set; }
}
}
24 changes: 24 additions & 0 deletions CrashReporter/Config/CrashReporter/CrashDumperConfig.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
namespace RJCP.Diagnostics.Config.CrashReporter
{
/// <summary>
/// CrashDumper Configuration.
/// </summary>
public class CrashDumperConfig
{
internal CrashDumperConfig()
{
DumpDir = new DumpDir();
}

internal CrashDumperConfig(CrashDumper config)
{
DumpDir = new DumpDir(config.DumpDir);
}

/// <summary>
/// Gets configuration properties for the dump directory.
/// </summary>
/// <value>The dump directory configuration properties.</value>
public DumpDir DumpDir { get; private set; }
}
}
102 changes: 102 additions & 0 deletions CrashReporter/Config/CrashReporter/DumpDir.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
namespace RJCP.Diagnostics.Config.CrashReporter
{
using System;

/// <summary>
/// Configuration on managing the dump directory.
/// </summary>
public class DumpDir
{
internal DumpDir()
{
Path = System.IO.Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
"CrashDumps");
AgeDays = 45;
MaxLogs = 40;
ReserveFree = 5;
ReserveFreePercent = 1;
MaxDirSize = 1;
MaxDirSizeMinLogs = 5;
}

internal DumpDir(DumpDirElement dumpDir) : this()
{
string path = Parser.ParseEnvVar(dumpDir.Path);
if (path != null) Path = path;

if (int.TryParse(dumpDir.AgeDays, out int ageDays)) {
if (ageDays <= 0) ageDays = 1;
AgeDays = ageDays;
}

if (int.TryParse(dumpDir.MaxLogs, out int maxLogs)) {
if (maxLogs <= 0) maxLogs = 1;
MaxLogs = maxLogs;
}

if (int.TryParse(dumpDir.ReserveFree, out int reserveFree)) {
if (reserveFree <= 0) reserveFree = 1;
ReserveFree = reserveFree;
}

if (int.TryParse(dumpDir.ReserveFreePercent, out int reserveFreePercent)) {
if (reserveFreePercent < 0) reserveFreePercent = 0;
if (reserveFreePercent > 99) reserveFreePercent = 99;
ReserveFreePercent = reserveFreePercent;
}

if (int.TryParse(dumpDir.MaxDirSize, out int maxDirSize)) {
if (maxDirSize <= 0) maxDirSize = 1;
MaxDirSize = maxDirSize;
}

if (int.TryParse(dumpDir.MaxDirSizeMinLogs, out int maxDirSizeMinLogs)) {
if (maxDirSizeMinLogs <= 0) maxDirSizeMinLogs = 1;
MaxDirSizeMinLogs = maxDirSizeMinLogs;
}
}

/// <summary>
/// Gets the directory path where to store the dump files.
/// </summary>
/// <value>The directory path where to store the dump files.</value>
public string Path { get; private set; }

/// <summary>
/// Gets the age, in days, from when to start removing old dump files.
/// </summary>
/// <value>The age days when to start removing old dump files.</value>
public int AgeDays { get; private set; }

/// <summary>
/// Gets the maximum logs to keep in the dump directory.
/// </summary>
/// <value>The maximum logs of logs to keep in the dump directory.</value>
public int MaxLogs { get; private set; }

/// <summary>
/// Gets the reserved free space in gigabytes.
/// </summary>
/// <value>The reserved free space in gigabytes.</value>
public int ReserveFree { get; private set; }

/// <summary>
/// Gets the reserved free space as a percentage.
/// </summary>
/// <value>The reserved free space as a percentage.</value>
public int ReserveFreePercent { get; private set; }

/// <summary>
/// Gets the maximum size of the dump directory.
/// </summary>
/// <value>The maximum size of the dump directory.</value>
public int MaxDirSize { get; private set; }

/// <summary>
/// Gets the minimum number of logs to keep if the max size of the directory is exceeded.
/// </summary>
/// <value>The minimum number of logs to keep if the max size of the directory is exceeded.</value>
public int MaxDirSizeMinLogs { get; private set; }
}
}
4 changes: 4 additions & 0 deletions CrashReporter/Config/CrashReporter/EnvVar/IToken.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
namespace RJCP.Diagnostics.Config.CrashReporter.EnvVar
{
internal interface IToken { }
}
17 changes: 17 additions & 0 deletions CrashReporter/Config/CrashReporter/EnvVar/TokenString.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace RJCP.Diagnostics.Config.CrashReporter.EnvVar
{
internal class TokenString : IToken
{
public TokenString(string value)
{
Value = value;
}

public string Value { get; private set; }

public override string ToString()
{
return Value;
}
}
}
44 changes: 44 additions & 0 deletions CrashReporter/Config/CrashReporter/EnvVar/TokenVar.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
namespace RJCP.Diagnostics.Config.CrashReporter.EnvVar
{
using System;
using System.IO;

internal class TokenVar : IToken
{
public TokenVar(string envVar)
{
if (envVar.Equals("LOCALAPPDATA", StringComparison.Ordinal)) {
Value = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
} else if (envVar.Equals("APPDATA", StringComparison.Ordinal)) {
Value = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
} else if (envVar.Equals("HOME", StringComparison.Ordinal)) {
if (Platform.IsWinNT()) {
string userProfile = Environment.GetEnvironmentVariable("USERPROFILE");
if (!string.IsNullOrWhiteSpace(userProfile)) {
Value = userProfile;
} else {
Value = string.Format("{0}{1}",
Environment.GetEnvironmentVariable("HOMEDRIVE"),
Environment.GetEnvironmentVariable("HOMEPATH"));
}
} else {
Value = Environment.GetEnvironmentVariable("HOME");
}
} else if (envVar.Equals("CWD", StringComparison.Ordinal)) {
Value = Environment.CurrentDirectory;
} else if (envVar.Equals("APPDIR", StringComparison.Ordinal)) {
string assemblyPath = System.Reflection.Assembly.GetExecutingAssembly().Location;
Value = Path.GetDirectoryName(assemblyPath);
} else {
Value = Environment.GetEnvironmentVariable(envVar);
}
}

public string Value { get; private set; }

public override string ToString()
{
return Value;
}
}
}
10 changes: 10 additions & 0 deletions CrashReporter/Config/CrashReporter/EnvVar/VarState.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace RJCP.Diagnostics.Config.CrashReporter.EnvVar
{
internal enum VarState
{
Expansion,
Token,
VariableStart,
Variable
}
}
Loading

0 comments on commit 01f5ac3

Please sign in to comment.