xamarin-macios/tests/xharness/Log.cs

259 строки
6.1 KiB
C#
Исходник Обычный вид История

using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.IO;
using System.Text;
using Xharness.Logging;
namespace Xharness
{
public class LogFile : Log, ILogFile
{
object lock_obj = new object ();
public string Path { get; private set; }
FileStream writer;
bool disposed;
public LogFile (ILogs logs, string description, string path, bool append = true)
: base (logs, description)
{
Path = path;
if (!append)
File.WriteAllText (path, string.Empty);
}
public override void Write (byte [] buffer, int offset, int count)
{
try {
// We don't want to open the file every time someone writes to the log, so we keep it as an instance
// variable until we're disposed. Due to the async nature of how we run tests, writes may still
// happen after we're disposed, in which case we create a temporary stream we close after writing
lock (lock_obj) {
var fs = writer;
if (fs == null) {
fs = new FileStream (Path, FileMode.Append, FileAccess.Write, FileShare.Read);
}
fs.Write (buffer, offset, count);
if (disposed) {
fs.Dispose ();
} else {
writer = fs;
}
}
} catch (Exception e) {
Console.WriteLine ($"Failed to write to the file {Path}: {e.Message}.");
return;
}
}
public override void Flush()
{
base.Flush();
if (writer != null && !disposed)
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));
}
protected override void Dispose (bool disposing)
{
base.Dispose (disposing);
if (writer != null) {
writer.Dispose ();
writer = null;
}
disposed = true;
}
}
// A log that writes to standard output
public class ConsoleLog : Log
{
StringBuilder captured = new StringBuilder ();
public ConsoleLog ()
: base (null)
{
}
public override void WriteImpl (string value)
{
captured.Append (value);
Console.Write (value);
}
public override string FullPath {
get {
throw new NotSupportedException ();
}
}
public override StreamReader GetReader ()
{
var str = new MemoryStream (System.Text.Encoding.UTF8.GetBytes (captured.ToString ()));
return new StreamReader (str, System.Text.Encoding.UTF8, false);
}
}
// A log that captures data written to a separate file between two moments in time
// (between StartCapture and StopCapture).
public class CaptureLog : Log
{
public string CapturePath { get; private set; }
public string Path { get; set; }
long startPosition;
long endPosition;
bool entire_file;
public CaptureLog (ILogs logs, string capture_path, bool entire_file = false)
: base (logs)
{
CapturePath = capture_path;
this.entire_file = entire_file;
}
public void StartCapture ()
{
if (entire_file)
return;
if (File.Exists (CapturePath))
startPosition = new FileInfo (CapturePath).Length;
}
public void StopCapture ()
{
[xharness] Add a file existence check. (#2478) Fixes this exception: ``` Harness exception for 'introspection': System.IO.FileNotFoundException: Could not find file '/Users/builder/Library/Logs/CoreSimulator/27618A4A-7E49-4BAB-8F77-FA938CE88682/system.log'. File name: '/Users/builder/Library/Logs/CoreSimulator/27618A4A-7E49-4BAB-8F77-FA938CE88682/system.log' at System.IO.__Error.WinIOError (System.Int32 errorCode, System.String maybeFullPath) [0x00207] in /private/tmp/source-mono-2017-04/bockbuild-2017-04/profiles/mono-mac-xamarin/build-root/mono-x64/mcs/class/referencesource/mscorlib/system/io/__error.cs:188 at System.IO.FileInfo.get_Length () [0x00038] in /private/tmp/source-mono-2017-04/bockbuild-2017-04/profiles/mono-mac-xamarin/build-root/mono-x64/mcs/class/referencesource/mscorlib/system/io/fileinfo.cs:171 at xharness.CaptureLog.StopCapture () [0x00021] in /Users/builder/jenkins/workspace/xamarin-macios-pr-builder/tests/xharness/Log.cs:252 at (wrapper remoting-invoke-with-check) xharness.CaptureLog:StopCapture () at xharness.AppRunner+<RunAsync>d__68.MoveNext () [0x0127f] in /Users/builder/jenkins/workspace/xamarin-macios-pr-builder/tests/xharness/AppRunner.cs:642 --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in /private/tmp/source-mono-2017-04/bockbuild-2017-04/profiles/mono-mac-xamarin/build-root/mono-x64/mcs/class/referencesource/mscorlib/system/runtime/exceptionservices/exceptionservicescommon.cs:151 at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x00037] in /private/tmp/source-mono-2017-04/bockbuild-2017-04/profiles/mono-mac-xamarin/build-root/mono-x64/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:187 at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x00028] in /private/tmp/source-mono-2017-04/bockbuild-2017-04/profiles/mono-mac-xamarin/build-root/mono-x64/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:156 at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x00008] in /private/tmp/source-mono-2017-04/bockbuild-2017-04/profiles/mono-mac-xamarin/build-root/mono-x64/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:128 at System.Runtime.CompilerServices.TaskAwaiter`1[TResult].GetResult () [0x00000] in /private/tmp/source-mono-2017-04/bockbuild-2017-04/profiles/mono-mac-xamarin/build-root/mono-x64/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:357 at xharness.RunSimulatorTask+<RunTestAsync>d__7.MoveNext () [0x0029d] in /Users/builder/jenkins/workspace/xamarin-macios-pr-builder/tests/xharness/Jenkins.cs:2894 --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in /private/tmp/source-mono-2017-04/bockbuild-2017-04/profiles/mono-mac-xamarin/build-root/mono-x64/mcs/class/referencesource/mscorlib/system/runtime/exceptionservices/exceptionservicescommon.cs:151 at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x00037] in /private/tmp/source-mono-2017-04/bockbuild-2017-04/profiles/mono-mac-xamarin/build-root/mono-x64/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:187 at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x00028] in /private/tmp/source-mono-2017-04/bockbuild-2017-04/profiles/mono-mac-xamarin/build-root/mono-x64/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:156 at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x00008] in /private/tmp/source-mono-2017-04/bockbuild-2017-04/profiles/mono-mac-xamarin/build-root/mono-x64/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:128 at System.Runtime.CompilerServices.TaskAwaiter.GetResult () [0x00000] in /private/tmp/source-mono-2017-04/bockbuild-2017-04/profiles/mono-mac-xamarin/build-root/mono-x64/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:113 at xharness.RunTestTask+<ExecuteAsync>d__8.MoveNext () [0x0010b] in /Users/builder/jenkins/workspace/xamarin-macios-pr-builder/tests/xharness/Jenkins.cs:2538 --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in /private/tmp/source-mono-2017-04/bockbuild-2017-04/profiles/mono-mac-xamarin/build-root/mono-x64/mcs/class/referencesource/mscorlib/system/runtime/exceptionservices/exceptionservicescommon.cs:151 at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x00037] in /private/tmp/source-mono-2017-04/bockbuild-2017-04/profiles/mono-mac-xamarin/build-root/mono-x64/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:187 at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x00028] in /private/tmp/source-mono-2017-04/bockbuild-2017-04/profiles/mono-mac-xamarin/build-root/mono-x64/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:156 at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x00008] in /private/tmp/source-mono-2017-04/bockbuild-2017-04/profiles/mono-mac-xamarin/build-root/mono-x64/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:128 at System.Runtime.CompilerServices.TaskAwaiter.GetResult () [0x00000] in /private/tmp/source-mono-2017-04/bockbuild-2017-04/profiles/mono-mac-xamarin/build-root/mono-x64/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:113 at xharness.TestTask+<RunInternalAsync>d__87.MoveNext () [0x0010d] in /Users/builder/jenkins/workspace/xamarin-macios-pr-builder/tests/xharness/Jenkins.cs:1870 ``` I'm not sure how this can happen, but it has on the bots [1]. [1] https://jenkins.mono-project.com/job/xamarin-macios-pr-builder/4548/Test_Report/
2017-08-11 19:23:15 +03:00
if (!File.Exists (CapturePath)) {
File.WriteAllText (Path, $"Could not capture the file '{CapturePath}' because it doesn't exist.");
return;
}
if (entire_file) {
File.Copy (CapturePath, Path, true);
return;
}
endPosition = new FileInfo (CapturePath).Length;
Capture ();
}
void Capture ()
{
if (startPosition == 0 || entire_file)
return;
[xharness] Be resilient when trying to copying contents from an inexistent file. (#4676) Should fix this (or at the very least not prevent xharness from writing out the report): 21:07:30.3947450 Failed to write log: System.IO.FileNotFoundException: Could not find file '/Users/builder/Library/Logs/CoreSimulator/6DA2ED3C-B1FA-4D0B-9DD6-113E5F9A1381/system.log'. File name: '/Users/builder/Library/Logs/CoreSimulator/6DA2ED3C-B1FA-4D0B-9DD6-113E5F9A1381/system.log' at System.IO.__Error.WinIOError (System.Int32 errorCode, System.String maybeFullPath) [0x00207] in /Users/builder/jenkins/workspace/build-package-osx-mono/2018-02/external/bockbuild/builds/mono-x64/mcs/class/referencesource/mscorlib/system/io/__error.cs:188 at System.IO.FileInfo.get_Length () [0x00038] in /Users/builder/jenkins/workspace/build-package-osx-mono/2018-02/external/bockbuild/builds/mono-x64/mcs/class/referencesource/mscorlib/system/io/fileinfo.cs:171 at xharness.CaptureLog.Capture () [0x0004a] in /Users/builder/jenkins/workspace/xamarin-macios/xamarin-macios/tests/xharness/Log.cs:334 at xharness.CaptureLog.Flush () [0x00008] in /Users/builder/jenkins/workspace/xamarin-macios/xamarin-macios/tests/xharness/Log.cs:373 at xharness.Jenkins.GenerateReportImpl (System.IO.Stream stream, System.IO.StreamWriter markdown_summary) [0x017db] in /Users/builder/jenkins/workspace/xamarin-macios/xamarin-macios/tests/xharness/Jenkins.cs:2012 at xharness.Jenkins.GenerateReport (System.Boolean only_if_ci) [0x00075] in /Users/builder/jenkins/workspace/xamarin-macios/xamarin-macios/tests/xharness/Jenkins.cs:1313
2018-08-22 17:54:19 +03:00
if (!File.Exists (CapturePath)) {
File.WriteAllText (Path, $"Could not capture the file '{CapturePath}' because it does not exist.");
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 (length < 0) {
// The file shrank?
return;
}
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);
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];
reader.Position = startPosition;
while (availableLength > 0) {
int read = reader.Read (buffer, 0, Math.Min (buffer.Length, length));
if (read > 0) {
writer.Write (buffer, 0, read);
availableLength -= read;
} else {
// There's nothing more to read.
// I can't see how we get here, since we calculate the amount to read based on what's available, but it does happen randomly.
break;
}
}
}
}
}
public override StreamReader GetReader ()
{
if (File.Exists (CapturePath)) {
return new StreamReader (new FileStream (CapturePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite));
} else {
return new StreamReader (new MemoryStream ());
}
}
public override void Flush ()
{
base.Flush ();
Capture ();
}
public override void WriteImpl (string value)
{
throw new InvalidOperationException ();
}
public override string FullPath {
get {
return Path;
}
}
}
// A log that forwards all written data to a callback
public class CallbackLog : Log
{
public Action<string> OnWrite;
public CallbackLog (Action<string> onWrite)
: base (null)
{
OnWrite = onWrite;
}
public override string FullPath => throw new NotImplementedException ();
public override void WriteImpl (string value)
{
OnWrite (value);
}
}
}