Extracting Log Files from a Package
The following code sample shows you how to extract log files from a package.
C#
//-----------------------------------------------------------------------
// <copyright file="CreateAPackage.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------
[assembly: System.CLSCompliant(true)]
namespace Microsoft.Windows.Kits.Samples
{
using System;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Collections.Generic;
using Microsoft.Windows.Kits.Hardware.ObjectModel;
using Microsoft.Windows.Kits.Hardware.ObjectModel.DBConnection;
using Microsoft.Windows.Kits.Hardware.ObjectModel.Submission;
internal static class ProgramSettings
{
internal static string PackagesDir = null;
internal static string PackageFile = null;
internal static bool ExtactLogs = false;
internal static string LogsDir = null;
internal static TextWriter Log = null;
internal static string LogFile = null;
internal static List<string> HCKCategoryLevels = null;
}
internal static class Constants
{
internal const string HckxExt = ".hckx";
internal const string DefaultLogName = "PackageAnalysisLog.txt";
}
public class PackageLogExtractor
{
static void Main(string[] args)
{
if (false == ParseArgs(args))
{
ShowUsage();
return;
}
PackageAnalyze(); // all the command line work.
if (ProgramSettings.Log != null)
{
ProgramSettings.Log.Dispose();
}
}
static void ShowUsage()
{
string usage = "";
usage += Environment.NewLine + "PackageLogExtractor.exe [/PackagesDir=<path>]" +
Environment.NewLine + " [/PackageFile=<path>]" +
Environment.NewLine + " [/ExtractLogsTo=<path>]" +
Environment.NewLine + " [/LogFile=<path>]" +
Environment.NewLine + " [/HCKLevelFilters=<Level1, Level2, ...>]" +
Environment.NewLine +
Environment.NewLine + "Any parameter in [] is optional." +
Environment.NewLine + "Atleast /PackagesDir or /PackageFile must be specified" +
Environment.NewLine +
Environment.NewLine + "PackageLogExtractor.exe /PackageFile=[FullPathwithHCKFILE.hckx] /LogFile=[FullPathwithLogFileName]" +
Environment.NewLine +
Environment.NewLine + "Parameter Descriptions:" +
Environment.NewLine + "======================================================================" +
Environment.NewLine +
Environment.NewLine + "PackagesDir: Directory to recursively search for Hckx files." +
Environment.NewLine +
Environment.NewLine + "PackageFile: Path to single Hckx file to process" +
Environment.NewLine +
Environment.NewLine + "ExtractLogsTo: Path to directory where extracted logs will be stored" +
Environment.NewLine +
Environment.NewLine + "LogFile: Path to file where to write the logging output to." +
Environment.NewLine +
Environment.NewLine + "HCKLevelFilters: A CSV list of HCK Content Categorization levels. Any combination of the following is supported: " +
Environment.NewLine + " Basic, Certification, Experiences, Functional, Optional, Reliability." +
Environment.NewLine + " Default is all levels." +
Environment.NewLine +
Environment.NewLine;
Console.WriteLine(usage);
}
static bool ParseArgs(string[] args)
{
if ((args.Length == 0) || (args[0].Contains("?")))
{
return false;
}
foreach (string arg in args)
{
if (arg.StartsWith("/PackagesDir=", StringComparison.OrdinalIgnoreCase))
{
ProgramSettings.PackagesDir = Path.GetFullPath(arg.Substring("/PackagesDir=".Length));
}
else if (arg.StartsWith("/PackageFile=", StringComparison.OrdinalIgnoreCase))
{
ProgramSettings.PackageFile = Path.GetFullPath(arg.Substring("/PackageFile=".Length));
}
else if (arg.StartsWith("/ExtractLogsTo=", StringComparison.OrdinalIgnoreCase))
{
ProgramSettings.LogsDir = Path.GetFullPath(arg.Substring("/ExtractLogsTo=".Length));
ProgramSettings.ExtactLogs = true;
}
else if (arg.StartsWith("/LogFile=", StringComparison.OrdinalIgnoreCase))
{
string logFile = Path.GetFullPath(arg.Substring("/LogFile=".Length));
if (!Directory.Exists(Path.GetDirectoryName(logFile)))
{
Directory.CreateDirectory(Path.GetDirectoryName(logFile));
}
ProgramSettings.LogFile = logFile;
if (false == string.IsNullOrWhiteSpace(ProgramSettings.LogFile))
{
try
{
ProgramSettings.Log = new StreamWriter(ProgramSettings.LogFile);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
}
else if (arg.StartsWith("/HCKLevelFilters=", StringComparison.OrdinalIgnoreCase))
{
ProgramSettings.HCKCategoryLevels =
new List<String>(arg.Substring("/HCKLevelFilters=".Length).ToUpperInvariant().Split(','));
}
else
{
Console.WriteLine("Unrecognized parameter: " + arg);
return false;
}
}
return true;
}
private static void WriteMessage(string message, params object[] args)
{
if (ProgramSettings.Log != null)
{
if (args.Length > 0)
{
ProgramSettings.Log.WriteLine(message, args);
}
else
{
ProgramSettings.Log.WriteLine(message);
}
}
else
{
Console.WriteLine(message, args);
}
}
///
/// <summary>
/// The Parse engine.
/// </summary>
///
public static void PackageAnalyze()
{
string[] packageFiles;
PackageManager manager = null;
List<ContentLevelType> hckCategoryLevels = null;
//
// Check category levels
//
if (null == ProgramSettings.HCKCategoryLevels)
{
hckCategoryLevels = new List<ContentLevelType>
{
ContentLevelType.Basic,
ContentLevelType.Certification,
ContentLevelType.Experiences,
ContentLevelType.Functional,
ContentLevelType.Optional,
ContentLevelType.Reliability
};
}
else if (0 != ProgramSettings.HCKCategoryLevels.Count)
{
hckCategoryLevels = new List<ContentLevelType>();
foreach (string cl in ProgramSettings.HCKCategoryLevels)
{
if ("Basic".ToUpperInvariant().Equals(cl.ToUpperInvariant()))
{
hckCategoryLevels.Add(ContentLevelType.Basic);
}
else if ("Certification".ToUpperInvariant().Equals(cl.ToUpperInvariant()))
{
hckCategoryLevels.Add(ContentLevelType.Certification);
}
else if ("Experiences".ToUpperInvariant().Equals(cl.ToUpperInvariant()))
{
hckCategoryLevels.Add(ContentLevelType.Experiences);
}
else if ("Functional".ToUpperInvariant().Equals(cl.ToUpperInvariant()))
{
hckCategoryLevels.Add(ContentLevelType.Functional);
}
else if ("Optional".ToUpperInvariant().Equals(cl.ToUpperInvariant()))
{
hckCategoryLevels.Add(ContentLevelType.Optional);
}
else if ("Reliability".ToUpperInvariant().Equals(cl.ToUpperInvariant()))
{
hckCategoryLevels.Add(ContentLevelType.Reliability);
}
else
{
Console.WriteLine(
string.Format(
"Invalid category level supplied {0}. \nAborting filtering and using all category levels.",
cl));
//
// Just stomp on it with a new one.
//
hckCategoryLevels = new List<ContentLevelType>
{
ContentLevelType.Basic,
ContentLevelType.Certification,
ContentLevelType.Experiences,
ContentLevelType.Functional,
ContentLevelType.Optional,
ContentLevelType.Reliability
};
}
}
}
if (string.IsNullOrEmpty(ProgramSettings.PackageFile) == false)
{
packageFiles = new string[] { ProgramSettings.PackageFile };
}
else
{
packageFiles = Directory.GetFiles(ProgramSettings.PackagesDir, "*.hckx", SearchOption.AllDirectories);
}
if (packageFiles.Count() == 0)
{
Console.WriteLine("No files in the specified directory");
}
else
{
foreach (var file in packageFiles)
{
try
{
WriteMessage("Process package {0}.", file);
manager = new PackageManager(file);
IList<Test> reportedTests = null;
List<Project> packageProjects = new List<Project>();
ReadOnlyCollection<string> projectNames = manager.GetProjectNames();
//
// First see if there's only 1 test result in this package. if so, don't create seperate sub directories for each result
//
foreach (var projectName in projectNames)
{
WriteMessage("Validating project: " + projectName);
bool packageHasResults = false;
ProjectInfo pi = manager.GetProjectInfo(projectName);
//
// We need to check results for every content level to make sure
//
foreach (ContentLevelRollupInfo cl in pi.RollupSummaryByContentLevels)
{
WriteMessage(
string.Format(
("Content level: {0}" +
"\n\tNot run test count: {1} equals total test run count: {2}"),
cl.ContentLevel,
cl.NotRunCount,
cl.TotalCount));
//
// See if the user wants to look for these levels first.
//
if (!hckCategoryLevels.Contains(cl.ContentLevel))
{
WriteMessage(
"Analyzer not configured to check results for content level: " + cl.ContentLevel);
continue;
}
//
// There wasn't anything run, so no files are going to exist.
// The OM is going to choke if you try to extract the log files later
// on.
//
if (cl.TotalCount == 0)
{
WriteMessage("No results for content level.");
continue;
}
else
{
WriteMessage(
string.Format(
("Results count for content level: {0} \n\t" +
"Pass - {1} Fail - {2} Running - {3} NotRun - {4} Total - {5}"),
cl.ContentLevel,
cl.PassedCount,
cl.FailedCount,
cl.RunningCount,
cl.NotRunCount,
cl.TotalCount));
packageHasResults = true;
}
}
if (true == packageHasResults)
{
var project = manager.GetProject(projectName);
packageProjects.Add(project);
//
// Report only tests which have results > 0.
//
reportedTests =
project.GetTests(hckCategoryLevels).Where(t => (t.GetTestResults().Count > 0)).ToList();
foreach (var test in reportedTests)
{
int resultCounter = 1;
foreach (var result in test.GetTestResults())
{
WriteMessage("=============================================");
string testTargetDevice = string.Join("; ", from a in test.GetTestTargets()
select a.Name);
WriteMessage("Test : " + test.Name);
WriteMessage("Target : " + testTargetDevice);
WriteMessage("RunTime (min): " + System.Math.Round((result.CompletionTime - result.StartTime).TotalMinutes));
string logsDir = ProgramSettings.LogsDir;
if (false == string.IsNullOrWhiteSpace(ProgramSettings.LogsDir))
{
logsDir = Path.Combine(ProgramSettings.LogsDir, project.Name, test.Name, "Result" + resultCounter.ToString(), test.GetTestTargets().First().Name);
foreach (var log in result.GetLogs().Where(x => x.LogType == LogType.TestRun))
{
log.WriteLogTo(Path.Combine(logsDir, "JobLogs", log.Name));
}
foreach (var log in result.GetLogs().Where(x => x.LogType == LogType.Gatherer))
{
log.WriteLogTo(Path.Combine(logsDir, "GathererLogs", log.Name));
}
foreach (var target in test.GetTestTargets())
{
string targetXmlDir = Path.Combine(logsDir, @"..\", "TargetXml");
if (!Directory.Exists(targetXmlDir))
{
try
{
Directory.CreateDirectory(targetXmlDir);
}
catch (Exception e)
{
Console.WriteLine("Directory creation failed", e.ToString());
}
}
File.WriteAllText(Path.Combine(targetXmlDir, (target.Name.Replace(" ", "_") + "_" + target.Machine.Name + ".xml")), target.XmlData);
}
ProcessResult(result.GetTasks(), Path.Combine(logsDir, "TaskLogs"), test);
}
else
{
ProcessResult(result.GetTasks(), null, test);
}
WriteMessage("=============================================");
resultCounter++;
}
}
}
}
}
catch (Exception e)
{
WriteMessage(e.ToString());
Console.WriteLine(e);
}
finally
{
if (manager != null)
manager.Dispose();
manager = null;
}
if (ProgramSettings.Log != null)
{
ProgramSettings.Log.Flush();
}
}
}
}
///
/// internal static void
/// ProcessResult(Task taskToProcess, string baseLogsDir, Test test, int indentLevel = 1)
///
/// <summary>
/// The primary result processing engine. Extracts log files for test tasks, validates results should
/// be reported for the task based on the WTT Task configuration extracted from the WTT infrastructure
/// log(s) and stored in the WTTTaskLogData list.
///
/// This is a recursive method as a particular task can have (n) child tasks.
/// </summary>
///
/// <param name="taskToProcess">
/// The HCK Task to process results for.
/// </param>
/// <param name="baseLogsDir">
/// Root log directory for the WTT Log files.
/// </param>
/// <param name="test">
/// The root HCK Test Object.
/// </param>
/// <param name="mergedWttLog">
/// Instance of the WTT Log we're pushing context in and out of
/// </param>
/// <param name="indentLevel">
/// For output purposes, indentation of the task information presented in the console window.
/// </param>
///
internal static void ProcessResult(IEnumerable<Task> tasksToProcess, string baseLogsDir, Test test, int indentLevel = 1)
{
List<Task> tasks = null;
tasks = tasksToProcess.OrderBy(x => x.TestResult.StartTime).ToList();
if (tasks.Count == 0)
{
return;
}
string msgIndent = new string('\t', indentLevel - 1);
foreach (var task in tasks)
{
if (string.IsNullOrWhiteSpace(baseLogsDir))
{
if (task.TaskType.Equals("RunJob", StringComparison.OrdinalIgnoreCase)) // recurse
{
ProcessResult(task.GetChildTasks(), null, test, indentLevel + 1);
}
}
else
{
string taskLogsDir = Path.Combine(baseLogsDir, task.Stage, task.Name);
if (task.TaskType.Equals("RunJob", StringComparison.OrdinalIgnoreCase)) // recurse
{
taskLogsDir = Path.Combine(baseLogsDir, task.Stage, "RunJob-" + task.Name);
ProcessResult(task.GetChildTasks(), taskLogsDir, test, indentLevel + 1);
}
else
{
foreach (var log in task.GetLogFiles())
{
log.WriteLogTo(Path.Combine(taskLogsDir, log.Name));
}
}
}
}
}
}
}