2016-06-17 18:21:18 +03:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Diagnostics.Contracts;
|
|
|
|
|
using System.IO;
|
2016-07-14 20:22:06 +03:00
|
|
|
|
using System.Text;
|
2016-06-17 18:21:18 +03:00
|
|
|
|
|
|
|
|
|
namespace xharness
|
|
|
|
|
{
|
2016-11-14 12:43:35 +03:00
|
|
|
|
public abstract class Log : TextWriter
|
2016-06-17 18:21:18 +03:00
|
|
|
|
{
|
|
|
|
|
public string Description;
|
2016-06-18 11:35:57 +03:00
|
|
|
|
public bool Timestamp;
|
2016-06-17 18:21:18 +03:00
|
|
|
|
|
|
|
|
|
protected Log ()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected Log (string description)
|
|
|
|
|
{
|
|
|
|
|
Description = description;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public abstract string FullPath { get; }
|
|
|
|
|
|
2016-06-18 11:35:57 +03:00
|
|
|
|
protected abstract void WriteImpl (string value);
|
2016-06-17 18:21:18 +03:00
|
|
|
|
|
|
|
|
|
public virtual StreamReader GetReader ()
|
|
|
|
|
{
|
|
|
|
|
throw new NotSupportedException ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual TextWriter GetWriter ()
|
|
|
|
|
{
|
|
|
|
|
throw new NotSupportedException ();
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-14 12:43:35 +03:00
|
|
|
|
public override void Write (string value)
|
2016-06-18 11:35:57 +03:00
|
|
|
|
{
|
|
|
|
|
if (Timestamp)
|
|
|
|
|
value = DateTime.Now.ToString ("HH:mm:ss.fffffff") + " " + value;
|
|
|
|
|
WriteImpl (value);
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-14 12:43:35 +03:00
|
|
|
|
public override void WriteLine (string value)
|
2016-06-17 18:21:18 +03:00
|
|
|
|
{
|
|
|
|
|
Write (value + "\n");
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-14 12:43:35 +03:00
|
|
|
|
public override void WriteLine (string format, params object [] args)
|
2016-06-17 18:21:18 +03:00
|
|
|
|
{
|
|
|
|
|
Write (string.Format (format, args) + "\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override string ToString ()
|
|
|
|
|
{
|
|
|
|
|
return Description;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-14 12:43:35 +03:00
|
|
|
|
public override void Flush ()
|
2016-06-18 11:35:57 +03:00
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-14 12:43:35 +03:00
|
|
|
|
public override Encoding Encoding {
|
|
|
|
|
get {
|
|
|
|
|
return System.Text.Encoding.UTF8;
|
|
|
|
|
}
|
2016-06-17 18:21:18 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class LogFile : Log
|
|
|
|
|
{
|
|
|
|
|
public string Path;
|
|
|
|
|
StreamWriter writer;
|
|
|
|
|
|
|
|
|
|
public LogFile (string description, string path)
|
|
|
|
|
: base (description)
|
|
|
|
|
{
|
|
|
|
|
Path = path;
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-18 11:35:57 +03:00
|
|
|
|
protected override void WriteImpl (string value)
|
2016-06-17 18:21:18 +03:00
|
|
|
|
{
|
|
|
|
|
lock (this) {
|
|
|
|
|
using (var str = new FileStream (Path, FileMode.Append, FileAccess.Write, FileShare.Read)) {
|
|
|
|
|
using (var writer = new StreamWriter (str)) {
|
|
|
|
|
writer.Write (value);
|
|
|
|
|
writer.Flush ();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override string FullPath {
|
|
|
|
|
get {
|
|
|
|
|
return Path;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override StreamReader GetReader ()
|
|
|
|
|
{
|
|
|
|
|
return new StreamReader (new FileStream (Path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override TextWriter GetWriter ()
|
|
|
|
|
{
|
2016-06-30 12:39:33 +03:00
|
|
|
|
return writer ?? (writer = new StreamWriter (new FileStream (Path, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Read)));
|
2016-06-17 18:21:18 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override void Dispose (bool disposing)
|
|
|
|
|
{
|
|
|
|
|
base.Dispose (disposing);
|
|
|
|
|
|
|
|
|
|
if (writer != null) {
|
|
|
|
|
writer.Dispose ();
|
|
|
|
|
writer = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class LogStream : Log
|
|
|
|
|
{
|
|
|
|
|
string path;
|
|
|
|
|
FileStream fs;
|
|
|
|
|
StreamWriter writer;
|
|
|
|
|
|
|
|
|
|
public FileStream FileStream {
|
|
|
|
|
get {
|
|
|
|
|
return fs;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override StreamReader GetReader ()
|
|
|
|
|
{
|
|
|
|
|
return new StreamReader (new FileStream (path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override TextWriter GetWriter ()
|
|
|
|
|
{
|
|
|
|
|
return writer ?? (writer = new StreamWriter (fs));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public LogStream (string description, string path)
|
|
|
|
|
: base (description)
|
|
|
|
|
{
|
|
|
|
|
this.path = path;
|
|
|
|
|
|
|
|
|
|
fs = new FileStream (path, FileMode.Create, FileAccess.Write, FileShare.Read);
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-18 11:35:57 +03:00
|
|
|
|
protected override void WriteImpl (string value)
|
2016-06-17 18:21:18 +03:00
|
|
|
|
{
|
|
|
|
|
var w = GetWriter ();
|
|
|
|
|
w.Write (value);
|
|
|
|
|
w.Flush ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override void Dispose (bool disposing)
|
|
|
|
|
{
|
|
|
|
|
base.Dispose (disposing);
|
|
|
|
|
|
|
|
|
|
if (writer != null) {
|
|
|
|
|
writer.Dispose ();
|
|
|
|
|
writer = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (fs != null) {
|
|
|
|
|
fs.Dispose ();
|
|
|
|
|
fs = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override string FullPath {
|
|
|
|
|
get {
|
|
|
|
|
return path;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class Logs : List<Log>
|
|
|
|
|
{
|
|
|
|
|
public LogStream CreateStream (string directory, string filename, string name)
|
|
|
|
|
{
|
|
|
|
|
Directory.CreateDirectory (directory);
|
|
|
|
|
var rv = new LogStream (name, Path.GetFullPath (Path.Combine (directory, filename)));
|
|
|
|
|
Add (rv);
|
|
|
|
|
return rv;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public LogFile CreateFile (string description, string path)
|
|
|
|
|
{
|
|
|
|
|
var rv = new LogFile (description, path);
|
|
|
|
|
Add (rv);
|
|
|
|
|
return rv;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class ConsoleLog : Log
|
|
|
|
|
{
|
2016-07-14 20:22:06 +03:00
|
|
|
|
StringBuilder captured = new StringBuilder ();
|
|
|
|
|
|
2016-06-18 11:35:57 +03:00
|
|
|
|
protected override void WriteImpl (string value)
|
2016-06-17 18:21:18 +03:00
|
|
|
|
{
|
2016-07-14 20:22:06 +03:00
|
|
|
|
captured.Append (value);
|
2016-06-17 18:21:18 +03:00
|
|
|
|
Console.Write (value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override string FullPath {
|
|
|
|
|
get {
|
|
|
|
|
throw new NotSupportedException ();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override TextWriter GetWriter ()
|
|
|
|
|
{
|
|
|
|
|
return Console.Out;
|
|
|
|
|
}
|
2016-07-14 20:22:06 +03:00
|
|
|
|
|
|
|
|
|
public override StreamReader GetReader ()
|
|
|
|
|
{
|
|
|
|
|
var str = new MemoryStream (System.Text.Encoding.UTF8.GetBytes (captured.ToString ()));
|
|
|
|
|
return new StreamReader (str, System.Text.Encoding.UTF8, false);
|
|
|
|
|
}
|
2016-06-17 18:21:18 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class CaptureLog : Log
|
|
|
|
|
{
|
|
|
|
|
public string CapturePath { get; private set; }
|
|
|
|
|
public string Path { get; set; }
|
|
|
|
|
|
2016-06-18 11:35:57 +03:00
|
|
|
|
long startPosition;
|
|
|
|
|
long endPosition;
|
2016-06-17 18:21:18 +03:00
|
|
|
|
|
|
|
|
|
public CaptureLog (string capture_path)
|
|
|
|
|
{
|
|
|
|
|
CapturePath = capture_path;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void StartCapture ()
|
|
|
|
|
{
|
|
|
|
|
if (File.Exists (CapturePath))
|
2016-06-18 11:35:57 +03:00
|
|
|
|
startPosition = new FileInfo (CapturePath).Length;
|
2016-06-17 18:21:18 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void StopCapture ()
|
|
|
|
|
{
|
2016-06-18 11:35:57 +03:00
|
|
|
|
endPosition = new FileInfo (CapturePath).Length;
|
|
|
|
|
|
|
|
|
|
Capture ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Capture ()
|
|
|
|
|
{
|
|
|
|
|
if (startPosition == 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
var currentEndPosition = endPosition;
|
|
|
|
|
if (currentEndPosition == 0)
|
|
|
|
|
currentEndPosition = new FileInfo (CapturePath).Length;
|
|
|
|
|
|
|
|
|
|
var length = (int) (currentEndPosition - startPosition);
|
|
|
|
|
var currentLength = new FileInfo (CapturePath).Length;
|
|
|
|
|
var capturedLength = 0L;
|
|
|
|
|
|
|
|
|
|
if (File.Exists (Path))
|
|
|
|
|
capturedLength = new FileInfo (Path).Length;
|
|
|
|
|
|
|
|
|
|
// capture 1k more data than when we stopped, since the system log
|
|
|
|
|
// is cached in memory and flushed once in a while (so when the app
|
|
|
|
|
// requests the system log to be captured, it's usually not complete).
|
|
|
|
|
var availableLength = currentLength - startPosition;
|
|
|
|
|
if (availableLength <= capturedLength)
|
|
|
|
|
return; // We've captured before, and nothing new as added since last time.
|
|
|
|
|
|
|
|
|
|
// Capture at most 1k more
|
|
|
|
|
availableLength = Math.Min (availableLength, length + 1024);
|
2016-06-17 18:21:18 +03:00
|
|
|
|
|
|
|
|
|
using (var reader = new FileStream (CapturePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) {
|
|
|
|
|
using (var writer = new FileStream (Path, FileMode.Create, FileAccess.Write, FileShare.Read)) {
|
|
|
|
|
var buffer = new byte [4096];
|
2016-06-18 11:35:57 +03:00
|
|
|
|
reader.Position = startPosition;
|
|
|
|
|
while (availableLength > 0) {
|
2016-06-17 18:21:18 +03:00
|
|
|
|
int read = reader.Read (buffer, 0, Math.Min (buffer.Length, length));
|
|
|
|
|
if (read > 0) {
|
|
|
|
|
writer.Write (buffer, 0, read);
|
2016-06-18 11:35:57 +03:00
|
|
|
|
availableLength -= read;
|
2016-06-17 18:21:18 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-18 11:35:57 +03:00
|
|
|
|
public override void Flush ()
|
|
|
|
|
{
|
|
|
|
|
base.Flush ();
|
|
|
|
|
|
|
|
|
|
Capture ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override void WriteImpl (string value)
|
2016-06-17 18:21:18 +03:00
|
|
|
|
{
|
|
|
|
|
throw new InvalidOperationException ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override string FullPath {
|
|
|
|
|
get {
|
|
|
|
|
return Path;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|