AcUtils
A high performance abstraction layer for AccuRev
AcDebug.cs
Go to the documentation of this file.
1 
16 using System;
17 using System.Diagnostics;
18 using System.IO;
19 using System.Xml.XPath;
20 using Microsoft.VisualBasic.Logging;
21 
22 namespace AcUtils
23 {
26 
69  public enum ParamFileCopy
70  {
90  };
92 
99  [Serializable]
100  public static class AcDebug
101  {
102  private static readonly string _trigTargetEnvVar = "AccuRevTriggers";
103 
108  public static string TrigTargetEnv
109  {
110  get { return _trigTargetEnvVar; }
111  }
112 
113  private static readonly string _trigTargetFile = "TriggersTarget.xml";
114  // global logging support
115  private static FileLogTraceListener _log;
116  [NonSerialized] private static readonly object _locker = new object();
117 
130 
131  public static bool paramFileCopy(string xmlFile, ParamFileCopy pfcopy, string trigger, string prncpl, string command)
132  {
133  bool ret = true; // assume success
134  try
135  {
136  if (pfcopy != ParamFileCopy.NoParamFileCopy)
137  {
138  if (
139  (pfcopy == ParamFileCopy.CopyParmFileTrigTarget &&
140  entryInTrigTargetsFile(trigger, prncpl)) ||
141  (pfcopy == ParamFileCopy.CopyParmFileContinue) ||
142  (pfcopy == ParamFileCopy.CopyParmFileExitSuccess) ||
143  (pfcopy == ParamFileCopy.CopyParmFileExitFailure)
144  )
145  {
146  string localappdata = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
147  string paramFolder = Path.Combine(localappdata, "AcTools\\Param");
148  if (!Directory.Exists(paramFolder))
149  Directory.CreateDirectory(paramFolder);
150  FileInfo fileInfoXml = new FileInfo(xmlFile);
151  string pFile;
152  if (String.IsNullOrEmpty(command))
153  {
154  // command is null in the case of server_post_promote
155  pFile = String.Format(@"{0}\{1}-{2}-{3}.xml",
156  paramFolder, trigger, prncpl, getStamp());
157  }
158  else
159  {
160  pFile = String.Format(@"{0}\{1}-{2}-{3}-{4}.xml",
161  paramFolder, trigger, command, prncpl, getStamp());
162  }
163 
164  fileInfoXml.CopyTo(pFile, true);
165  if (pfcopy == ParamFileCopy.CopyParmFileExitSuccess)
166  Environment.Exit(0);
167  else if (pfcopy == ParamFileCopy.CopyParmFileExitFailure)
168  Environment.Exit(1);
169  }
170  }
171  }
172 
173  catch (Exception ecx)
174  {
175  Log($"Exception caught and logged in AcDebug.paramFileCopy(string, ParamFileCopy, string, string, string){Environment.NewLine}{ecx.Message}");
176  ret = false;
177  }
178 
179  return ret;
180  }
181 
199 
200  public static bool paramFileCopy(ParamFileCopy pfcopy, string xml, string trigger, string prncpl)
201  {
202  bool ret = true; // assume success
203  try
204  {
205  if (pfcopy != ParamFileCopy.NoParamFileCopy)
206  {
207  if (
208  (pfcopy == ParamFileCopy.CopyParmFileTrigTarget &&
209  entryInTrigTargetsFile(trigger, prncpl)) ||
210  (pfcopy == ParamFileCopy.CopyParmFileContinue) ||
211  (pfcopy == ParamFileCopy.CopyParmFileExitSuccess) ||
212  (pfcopy == ParamFileCopy.CopyParmFileExitFailure)
213  )
214  {
215  string localappdata = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
216  string paramFolder = Path.Combine(localappdata, "AcTools\\Param");
217  if (!Directory.Exists(paramFolder))
218  Directory.CreateDirectory(paramFolder);
219  string pFile = String.Format(@"{0}\{1}-{2}-{3}.xml",
220  paramFolder, trigger, prncpl, getStamp());
221  createParamFile(pFile, xml);
222  if (pfcopy == ParamFileCopy.CopyParmFileExitSuccess)
223  Environment.Exit(0);
224  else if (pfcopy == ParamFileCopy.CopyParmFileExitFailure)
225  Environment.Exit(1);
226  }
227  }
228  }
229 
230  catch (Exception ecx)
231  {
232  Log($"Exception caught and logged in AcDebug.paramFileCopy(ParamFileCopy, string, string, string){Environment.NewLine}{ecx.Message}");
233  ret = false;
234  }
235 
236  return ret;
237  }
238 
248  private static void createParamFile(string fileName, string content)
249  {
250  FileStream fs = null;
251  try
252  {
253  if (File.Exists(fileName)) // highly unlikely it would exist but check anyway
254  File.Delete(fileName);
255 
256  fs = new FileStream(fileName, FileMode.Create);
257  using (StreamWriter sw = new StreamWriter(fs))
258  {
259  sw.Write(content);
260  }
261  }
262 
263  catch (Exception exc)
264  {
265  String msg = String.Format("Exception in AcDebug.createParamFile caught and logged.{0}{1}{0}Filename: {2}{0}{3}",
266  Environment.NewLine, exc.Message, fileName, content);
267  Log(msg);
268  }
269 
270  finally // avoids CA2202: Do not dispose objects multiple times
271  {
272  if (fs != null) fs.Dispose();
273  }
274  }
275 
281  private static string getStamp()
282  {
283  string stamp = DateTime.Now.Year.ToString() + DateTime.Now.Month.ToString() + DateTime.Now.Day.ToString() +
284  DateTime.Now.Hour.ToString() + DateTime.Now.Minute.ToString() + DateTime.Now.Second.ToString() +
285  DateTime.Now.Millisecond.ToString();
286  return stamp;
287  }
288 
306 
332  private static bool entryInTrigTargetsFile(string trigger, string prncpl)
333  {
334  try
335  {
336  string triggersFolder = Environment.GetEnvironmentVariable(_trigTargetEnvVar);
337  if (triggersFolder != null) // if the AccuRevTriggers environment variable is set
338  {
339  string xmlTriggersFile = Path.Combine(triggersFolder, _trigTargetFile);
340  XPathDocument doc = new XPathDocument(xmlTriggersFile);
341  XPathNavigator nav = doc.CreateNavigator();
342  XPathNodeIterator iterDebug = nav.Select($"Triggers/Trigger[@Name='{trigger}']/Principal");
343  foreach (XPathNavigator iterCmd in iterDebug) // iterate thru all principals in TriggersTarget.xml
344  {
345  string name = iterCmd.GetAttribute("Name", String.Empty);
346  if (String.Equals(prncpl, name))
347  {
348  return true;
349  }
350  }
351  }
352  }
353 
354  catch (XPathException ecx)
355  {
356  Log($"XPathException in AcDebug.entryInTrigTargetsFile caught and logged.{Environment.NewLine}{ecx.Message}");
357  }
358 
359  catch (Exception exc)
360  {
361  String msg = String.Format("Exception in AcDebug.entryInTrigTargetsFile caught and logged.{0}Trigger: {1}{0}Principal: {2}{0}{3}",
362  Environment.NewLine, trigger, prncpl, exc.Message);
363  Log(msg);
364  }
365 
366  return false;
367  }
368 
377 
378  public static void Log(string message, bool formatting = true)
379  {
380  lock (_locker)
381  {
382  Console.WriteLine(message); // to STDOUT and trigger.log
383  if (_log != null)
384  {
385  if (formatting)
386  // include date/time in our log file and separate each log entry with an empty line
387  _log.WriteLine($"{DateTime.Now.ToString()}{Environment.NewLine}{message}{Environment.NewLine}");
388  else
389  _log.WriteLine(message);
390  }
391  }
392  }
393 
412 
413  public static void Log(string message, string xmlParamFile, bool formatting = true)
414  {
415  Log(message, formatting);
416  try
417  {
418  // Overwrite the XML param file to display our custom message text in the error dialog given
419  // to the user. Otherwise, the contents of the XML param file will display (yuck).
420  using (StreamWriter writer = new StreamWriter(xmlParamFile, false)) // false to overwrite file
421  {
422  writer.WriteLine(message);
423  }
424  }
425 
426  catch (Exception e) // IOException, DirectoryNotFoundException, PathTooLongException, SecurityException... others
427  {
428  Log($"Unable to overwrite XML param file {xmlParamFile}{Environment.NewLine}{e.Message}");
429  }
430  }
431 
441 
445 
471  public static bool initAcLogging()
472  {
473  bool ret = false; // assume failure
474  try
475  {
476  // Get root name of our executable for initializing our TraceSource object below.
477  // This name must be specified in the application's .config file for logging to work.
478  string exeRootName = String.Empty;
479  using (Process currentProcess = Process.GetCurrentProcess())
480  {
481  ProcessModule pm = currentProcess.MainModule;
482  string module = pm.ModuleName;
483  exeRootName = Path.GetFileNameWithoutExtension(module);
484  }
485 
486  string localappdata = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
487  string logsFolder = Path.Combine(localappdata, "AcTools\\Logs");
488  if (!Directory.Exists(logsFolder))
489  Directory.CreateDirectory(logsFolder);
490 
491  TraceSource ts = new TraceSource(exeRootName);
492  _log = (FileLogTraceListener)ts.Listeners["AcLog"];
493  _log.Location = LogFileLocation.Custom;
494  _log.CustomLocation = logsFolder;
495  // our log file name begins with this name
496  _log.BaseFileName = exeRootName;
497  // allow log files to grow up to 40 megabytes in size
498  //_log.MaxFileSize = 41943040;
499  // allow log files to grow up to 80 megabytes in size
500  _log.MaxFileSize = 83886080;
501  // at least 2.3GB free disk space must exist for logging to continue
502  _log.ReserveDiskSpace = 2500000000;
503  // use the first day of the current week in the log file name
504  _log.LogFileCreationSchedule = LogFileCreationScheduleOption.Weekly;
505  // true to make sure we capture data in the event of an exception
506  _log.AutoFlush = true;
507  ret = true;
508  }
509 
510  catch (Exception exc)
511  {
512  Console.WriteLine($"Exception caught in AcDebug.initAcLogging{Environment.NewLine}{exc.Message}");
513  }
514 
515  return ret;
516  }
517 
525  public static string getLogFile()
526  {
527  string logfile = null;
528  if (_log != null) // if logging support was initialized
529  // referencing FullLogFileName property will create a zero-byte log file if it doesn't exist
530  logfile = _log.FullLogFileName;
531  return logfile;
532  }
533 
538 
543  public static void unhandledException(object sender, UnhandledExceptionEventArgs args)
544  {
545  Exception e = (Exception)args.ExceptionObject;
546  AcDebug.Log(e.ToString(), false);
547  }
548 
554  public static void errorDataHandler(object sendingProcess, DataReceivedEventArgs errLine)
555  {
556  if (!String.IsNullOrEmpty(errLine.Data))
557  {
558  string errline = errLine.Data.Trim();
559  // Report error if something other than "not in a directory associated with a workspace"
560  if (errline.Length > 0 &&
561  !String.Equals("You are not in a directory associated with a workspace", errline))
562  {
563  AcDebug.Log(errline);
564  }
565  }
566  }
567  }
568 }
static void Log(string message, string xmlParamFile, bool formatting=true)
Used by triggers, this method overload includes all functionality of Log(string, bool) and adds overw...
Definition: AcDebug.cs:413
static bool paramFileCopy(ParamFileCopy pfcopy, string xml, string trigger, string prncpl)
Used by the server_auth_trig to save the content of the XML param data passed to it by AccuRev to %LO...
Definition: AcDebug.cs:200
static void unhandledException(object sender, UnhandledExceptionEventArgs args)
Ensure that an unhandled exception gets logged to %LOCALAPPDATA%\AcTools\Logs\-YYYY-MM-DD...
Definition: AcDebug.cs:543
CopyParmFileTrigTarget
ParamFileCopy
For trigger development, debugging, and troubleshooting.
Definition: AcDebug.cs:69
CopyParmFileExitFailure
static bool initAcLogging()
Initialize application logging support, for general purpose or error messages, in conjunction with a ...
Definition: AcDebug.cs:471
CopyParmFileContinue
static void Log(string message, bool formatting=true)
Write the message text to STDOUT, to weekly log files located in %LOCALAPPDATA%\AcTools\Logs, and to trigger.log in the AccuRev server's ..storage\site_slice\logs folder in the case of triggers.
Definition: AcDebug.cs:378
static void errorDataHandler(object sendingProcess, DataReceivedEventArgs errLine)
Centralized error handler.
Definition: AcDebug.cs:554
static string getLogFile()
Get the log file's full path name.
Definition: AcDebug.cs:525
static string TrigTargetEnv
Returns "AccuRevTriggers", the name of the environment variable on the AccuRev server that points to ...
Definition: AcDebug.cs:109
static string getStamp()
Helper function for creating a unique filename for our copy of the XML param data.
Definition: AcDebug.cs:281
static void createParamFile(string fileName, string content)
Helper function that creates the XML param data copy.
Definition: AcDebug.cs:248
Use to log and display error and general purpose text messages, and to save the XML param data sent b...
Definition: AcDebug.cs:100
static bool paramFileCopy(string xmlFile, ParamFileCopy pfcopy, string trigger, string prncpl, string command)
Used by a trigger to save the content of the XML param file passed to it by AccuRev to %LOCALAPPDATA%...
Definition: AcDebug.cs:131
static bool entryInTrigTargetsFile(string trigger, string prncpl)
Determine if an entry exists for this user and trigger combo in TriggersTarget.xml.
Definition: AcDebug.cs:332
CopyParmFileExitSuccess