Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
The following code sample shows you how to extract log files from a package.
C#
//-----------------------------------------------------------------------
// <copyright file="PackageLogExtractor.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 System.Xml;
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 ExtractLogs = false;
internal static string LogsDir = null;
internal static TextWriter Log = null;
internal static string LogFile = null;
internal static List<string> DevelopmentPhases = null;
}
internal static class Constants
{
internal const string PackageExt = ".hlkx";
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 + " [/PhaseFilters=<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.hlkx] /LogFile=[FullPathwithLogFileName]" +
Environment.NewLine +
Environment.NewLine + "Parameter Descriptions:" +
Environment.NewLine + "======================================================================" +
Environment.NewLine +
Environment.NewLine + "PackagesDir: Directory to recursively search for package files." +
Environment.NewLine +
Environment.NewLine + "PackageFile: Path to single package 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 + "PhaseFilters: A CSV list of HLK Development Phases. Any combination of the following is supported: " +
Environment.NewLine + " BringUp, DevelopmentAndIntegration, Manufacturing, Reliability, Support, TuningAndValidation." +
Environment.NewLine + " Default is all phases." +
Environment.NewLine +
Environment.NewLine;
//*** Need to update that
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.ExtractLogs = 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("/PhaseFilters=", StringComparison.OrdinalIgnoreCase))
{
ProgramSettings.DevelopmentPhases =
new List<String>(arg.Substring("/PhaseFilters=".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<DevelopmentPhase> developmentPhases = null;
//
// Check development phases
//
if (null == ProgramSettings.DevelopmentPhases)
{
var phases = (DevelopmentPhase[])Enum.GetValues(typeof(DevelopmentPhase));
developmentPhases = new List<DevelopmentPhase>(phases);
}
else if (0 != ProgramSettings.DevelopmentPhases.Count)
{
developmentPhases = new List<DevelopmentPhase>();
Func<string, string, bool> PhasesMatch = (left, right) => {
return string.Equals(left, right, StringComparison.OrdinalIgnoreCase);
};
foreach (string phase in ProgramSettings.DevelopmentPhases)
{
if (PhasesMatch("BringUp", phase))
{
developmentPhases.Add(DevelopmentPhase.BringUp);
}
else if (PhasesMatch("DevelopmentAndIntegration", phase))
{
developmentPhases.Add(DevelopmentPhase.DevelopmentAndIntegration);
}
else if (PhasesMatch("Manufacturing", phase))
{
developmentPhases.Add(DevelopmentPhase.Manufacturing);
}
else if (PhasesMatch("Reliability", phase))
{
developmentPhases.Add(DevelopmentPhase.Reliability);
}
else if (PhasesMatch("Support", phase))
{
developmentPhases.Add(DevelopmentPhase.Support);
}
else if (PhasesMatch("TuningAndValidation", phase))
{
developmentPhases.Add(DevelopmentPhase.TuningAndValidation);
}
else
{
Console.WriteLine(
string.Format(
"Invalid category level supplied {0}. \nAborting filtering and using all category levels.",
phase));
//
// Just stomp on it with a new one.
//
var phases = (DevelopmentPhase[])Enum.GetValues(typeof(DevelopmentPhase));
developmentPhases = new List<DevelopmentPhase>(phases);
}
}
}
if (string.IsNullOrEmpty(ProgramSettings.PackageFile) == false)
{
packageFiles = new string[] { ProgramSettings.PackageFile };
}
else
{
//*** Same extension?
packageFiles = Directory.GetFiles(ProgramSettings.PackagesDir, "*.hlkx", SearchOption.AllDirectories);
}
if (packageFiles.Count() == 0)
{
Console.WriteLine("No files in the specified directory");
}
else
{
foreach (var file in packageFiles)
{
try
{
ProcessFile(manager, file, developmentPhases);
}
catch (Exception e)
{
WriteMessage(e.ToString());
Console.WriteLine(e);
}
finally
{
if (manager != null)
{
manager.Dispose();
}
manager = null;
}
if (ProgramSettings.Log != null)
{
ProgramSettings.Log.Flush();
}
}
}
}
static void ProcessFile(ProjectManager manager, string file, List<DevelopmentPhase> developmentPhases)
{
WriteMessage("Process package {0}.", file);
manager = new PackageManager(file);
List<Project> packageProjects = new List<Project>();
ReadOnlyCollection<string> projectNames = manager.GetProjectNames();
foreach (var projectName in projectNames)
{
WriteMessage("Validating project: " + projectName);
bool packageHasResults = false;
ProjectInfo info = manager.GetProjectInfo(projectName);
//
// 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 (info.TotalCount == 0)
{
WriteMessage("No results.");
continue;
}
else
{
WriteMessage(
string.Format(
("Results count: \n\t" +
"Pass - {0} Fail - {1} Running - {2} NotRun - {3} Total - {4}"),
info.PassedCount,
info.FailedCount,
info.RunningCount,
info.NotRunCount,
info.TotalCount));
packageHasResults = true;
}
if (packageHasResults)
{
var project = manager.GetProject(projectName);
packageProjects.Add(project);
//
// Create a list of tests which satisfy filtering condition
//
IList<Test> testList = project.GetTests().SelectMany((t => t.DevelopmentPhases.Join(developmentPhases, p => p, d => d, (p, d) => t))).ToList();
//
// Report only tests which have results > 0.
//
foreach (Test test in testList.Where(t => (t.GetTestResults().Count > 0)))
{
ProcessTest(test, project.Name);
}
}
}
}
static void ProcessTest(Test test, string projectName)
{
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, projectName, 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());
}
}
string fileName = target.Name.Replace(" ", "_") + "_" + target.Machine.Name + ".xml";
File.WriteAllText(Path.Combine(targetXmlDir, fileName), target.XmlData);
}
ProcessResult(result.GetTasks(), Path.Combine(logsDir, "TaskLogs"), test);
}
else
{
ProcessResult(result.GetTasks(), null, test);
}
WriteMessage("=============================================");
resultCounter++;
}
}
/// <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 many child tasks.
/// </summary>
/// <param name="taskToProcess">
/// The HLK Task to process results for.
/// </param>
/// <param name="baseLogsDir">
/// Root log directory for the WTT Log files.
/// </param>
/// <param name="test">
/// The root HLK 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>
static void ProcessResult(IEnumerable<Task> tasksToProcess, string baseLogsDir, Test test, int indentLevel = 1)
{
List<Task> 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));
}
}
}
}
}
}
}