Skip to content

Commit

Permalink
Make telemetry logger per context and send summary event on destructi…
Browse files Browse the repository at this point in the history
…on (#1718)
  • Loading branch information
yao-msft authored Nov 30, 2021
1 parent 73d35a2 commit cc2dd14
Show file tree
Hide file tree
Showing 24 changed files with 734 additions and 300 deletions.
6 changes: 3 additions & 3 deletions src/AppInstallerCLICore/COMContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,18 +44,18 @@ namespace AppInstaller::CLI::Execution
FireCallbacks(ReportType::EndProgress, 0, 0, ProgressType::None, m_executionStage);
};

void COMContext::SetExecutionStage(CLI::Workflow::ExecutionStage executionStage, bool)
void COMContext::SetExecutionStage(CLI::Workflow::ExecutionStage executionStage)
{
m_executionStage = executionStage;
FireCallbacks(ReportType::ExecutionPhaseUpdate, 0, 0, ProgressType::None, m_executionStage);
Logging::SetExecutionStage(static_cast<uint32_t>(m_executionStage));
GetThreadGlobals().GetTelemetryLogger().SetExecutionStage(static_cast<uint32_t>(m_executionStage));
}

void COMContext::SetContextLoggers(const std::wstring_view telemetryCorrelationJson, const std::string& caller)
{
m_correlationData = telemetryCorrelationJson;

std::unique_ptr<AppInstaller::ThreadLocalStorage::PreviousThreadGlobals> setThreadGlobalsToPreviousState = GetThreadGlobals().SetForCurrentThread();
std::unique_ptr<AppInstaller::ThreadLocalStorage::PreviousThreadGlobals> setThreadGlobalsToPreviousState = this->SetForCurrentThread();

SetLoggers();
GetThreadGlobals().GetTelemetryLogger().SetTelemetryCorrelationJson(telemetryCorrelationJson);
Expand Down
2 changes: 1 addition & 1 deletion src/AppInstallerCLICore/COMContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ namespace AppInstaller::CLI::Execution
void EndProgress(bool) override;

//Execution::Context
void SetExecutionStage(CLI::Workflow::ExecutionStage executionPhase, bool);
void SetExecutionStage(CLI::Workflow::ExecutionStage executionPhase);

CLI::Workflow::ExecutionStage GetExecutionStage() const { return m_executionStage; }

Expand Down
4 changes: 3 additions & 1 deletion src/AppInstallerCLICore/Commands/CompleteCommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,10 @@ namespace AppInstaller::CLI
}

// Create a new Context to execute the Complete from
auto subContextPtr = context.Clone();
auto subContextPtr = context.CreateSubContext();
Context& subContext = *subContextPtr;
auto previousThreadGlobals = subContext.SetForCurrentThread();

subContext.Reporter.SetChannel(Execution::Reporter::Channel::Completion);
subContext.Add<Data::CompletionData>(std::move(data));

Expand Down
2 changes: 1 addition & 1 deletion src/AppInstallerCLICore/ContextOrchestrator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ namespace AppInstaller::CLI::Execution
{
std::unique_ptr<Command> command = item->PopNextCommand();

std::unique_ptr<AppInstaller::ThreadLocalStorage::PreviousThreadGlobals> setThreadGlobalsToPreviousState = item->GetContext().GetThreadGlobals().SetForCurrentThread();
std::unique_ptr<AppInstaller::ThreadLocalStorage::PreviousThreadGlobals> setThreadGlobalsToPreviousState = item->GetContext().SetForCurrentThread();

item->GetContext().GetThreadGlobals().GetTelemetryLogger().LogCommand(command->FullName());
command->ValidateArguments(item->GetContext().Args);
Expand Down
9 changes: 6 additions & 3 deletions src/AppInstallerCLICore/Core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,12 @@ namespace AppInstaller::CLI
}
#endif

Logging::UseGlobalTelemetryLoggerActivityIdOnly();

Execution::Context context{ std::cout, std::cin };
auto previousThreadGlobals = context.SetForCurrentThread();
context.EnableCtrlHandler();

// Enable all logging for this phase; we will update once we have the arguments
Logging::Log().EnableChannel(Logging::Channel::All);
Logging::Log().SetLevel(Logging::Level::Info);
Expand All @@ -73,9 +79,6 @@ namespace AppInstaller::CLI
// Initiate the background cleanup of the log file location.
Logging::BeginLogFileCleanup();

Execution::Context context{ std::cout, std::cin };
context.EnableCtrlHandler();

context << Workflow::ReportExecutionStage(Workflow::ExecutionStage::ParseArgs);

// Convert incoming wide char args to UTF8
Expand Down
16 changes: 11 additions & 5 deletions src/AppInstallerCLICore/ExecutionContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,9 @@ namespace AppInstaller::CLI::Execution
}
}

std::unique_ptr<Context> Context::Clone()
std::unique_ptr<Context> Context::CreateSubContext()
{
auto clone = std::make_unique<Context>(Reporter);
auto clone = std::make_unique<Context>(Reporter, m_threadGlobals);
clone->m_flags = m_flags;
// If the parent is hooked up to the CTRL signal, have the clone be as well
if (m_disableCtrlHandlerOnExit)
Expand Down Expand Up @@ -184,6 +184,7 @@ namespace AppInstaller::CLI::Execution
void Context::SetTerminationHR(HRESULT hr)
{
m_terminationHR = hr;
m_isTerminated = true;
}

void Context::Cancel(bool exitIfStuck, bool bypassUser)
Expand All @@ -192,26 +193,31 @@ namespace AppInstaller::CLI::Execution
Reporter.CancelInProgressTask(bypassUser);
}

void Context::SetExecutionStage(Workflow::ExecutionStage stage, bool allowBackward)
void Context::SetExecutionStage(Workflow::ExecutionStage stage)
{
if (m_executionStage == stage)
{
return;
}
else if (m_executionStage > stage && !allowBackward)
else if (m_executionStage > stage)
{
THROW_HR_MSG(HRESULT_FROM_WIN32(ERROR_INVALID_STATE), "Reporting ExecutionStage to an earlier Stage without allowBackward as true");
}

m_executionStage = stage;
Logging::SetExecutionStage(static_cast<uint32_t>(m_executionStage));
GetThreadGlobals().GetTelemetryLogger().SetExecutionStage(static_cast<uint32_t>(m_executionStage));
}

AppInstaller::ThreadLocalStorage::ThreadGlobals& Context::GetThreadGlobals()
{
return m_threadGlobals;
}

std::unique_ptr<AppInstaller::ThreadLocalStorage::PreviousThreadGlobals> Context::SetForCurrentThread()
{
return m_threadGlobals.SetForCurrentThread();
}

#ifndef AICLI_DISABLE_TEST_HOOKS
bool Context::ShouldExecuteWorkflowTask(const Workflow::WorkflowTask& task)
{
Expand Down
16 changes: 10 additions & 6 deletions src/AppInstallerCLICore/ExecutionContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,10 @@ namespace AppInstaller::CLI::Execution
{
Context(std::ostream& out, std::istream& in) : Reporter(out, in) {}

// Clone the reporter for this constructor.
Context(Execution::Reporter& reporter) : Reporter(reporter, Execution::Reporter::clone_t{}) {}
// Constructor for creating a sub-context.
Context(Execution::Reporter& reporter, ThreadLocalStorage::ThreadGlobals& threadGlobals) :
Reporter(reporter, Execution::Reporter::clone_t{}),
m_threadGlobals(threadGlobals, ThreadLocalStorage::ThreadGlobals::create_sub_thread_globals_t{}) {}

virtual ~Context();

Expand All @@ -81,8 +83,8 @@ namespace AppInstaller::CLI::Execution
// The arguments given to execute with.
Args Args;

// Creates a copy of this context as it was at construction.
virtual std::unique_ptr<Context> Clone();
// Creates a child of this context.
virtual std::unique_ptr<Context> CreateSubContext();

// Enables reception of CTRL signals.
void EnableCtrlHandler(bool enabled = true);
Expand Down Expand Up @@ -125,11 +127,13 @@ namespace AppInstaller::CLI::Execution
WI_ClearAllFlags(m_flags, flags);
}

virtual void SetExecutionStage(Workflow::ExecutionStage stage, bool);
virtual void SetExecutionStage(Workflow::ExecutionStage stage);

// Get Globals for Current Thread
// Get Globals for Current Context
AppInstaller::ThreadLocalStorage::ThreadGlobals& GetThreadGlobals();

std::unique_ptr<AppInstaller::ThreadLocalStorage::PreviousThreadGlobals> SetForCurrentThread();

#ifndef AICLI_DISABLE_TEST_HOOKS
// Enable tests to override behavior
bool ShouldExecuteWorkflowTask(const Workflow::WorkflowTask& task);
Expand Down
33 changes: 2 additions & 31 deletions src/AppInstallerCLICore/ExecutionContextData.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,36 +53,7 @@ namespace AppInstaller::CLI::Execution
Max
};

// Contains all the information needed to install a package.
// This is used when installing multiple packages to pass all the
// data to a sub-context.
struct PackageToInstall
{
PackageToInstall(
std::shared_ptr<Repository::IPackageVersion>&& packageVersion,
std::shared_ptr<Repository::IPackageVersion>&& installedPackageVersion,
Manifest::Manifest&& manifest,
Manifest::ManifestInstaller&& installer,
Manifest::ScopeEnum scope = Manifest::ScopeEnum::Unknown,
uint32_t packageSubExecutionId = 0)
: PackageVersion(std::move(packageVersion)), InstalledPackageVersion(std::move(installedPackageVersion)), Manifest(std::move(manifest)), Installer(std::move(installer)), Scope(scope), PackageSubExecutionId(packageSubExecutionId) { }

std::shared_ptr<Repository::IPackageVersion> PackageVersion;

// Used to uninstall the old version if needed.
std::shared_ptr<Repository::IPackageVersion> InstalledPackageVersion;

// Use this instead of the PackageVersion->GetManifest() as the locale was
// applied when selecting the installer.
Manifest::Manifest Manifest;

Manifest::ManifestInstaller Installer;
Manifest::ScopeEnum Scope = Manifest::ScopeEnum::Unknown;

// Use this sub execution id when installing this package so that
// install telemetry is captured with the same sub execution id as other events in Search phase.
uint32_t PackageSubExecutionId = 0;
};
struct Context;

namespace details
{
Expand Down Expand Up @@ -203,7 +174,7 @@ namespace AppInstaller::CLI::Execution
template <>
struct DataMapping<Data::PackagesToInstall>
{
using value_t = std::vector<PackageToInstall>;
using value_t = std::vector<std::unique_ptr<Context>>;
};

template <>
Expand Down
68 changes: 54 additions & 14 deletions src/AppInstallerCLICore/Workflows/DependenciesFlow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,33 @@ using namespace AppInstaller::Manifest;

namespace AppInstaller::CLI::Workflow
{
namespace
{
// Contains all the information needed to install a dependency package.
struct DependencyPackageCandidate
{
DependencyPackageCandidate(
std::shared_ptr<Repository::IPackageVersion>&& packageVersion,
std::shared_ptr<Repository::IPackageVersion>&& installedPackageVersion,
Manifest::Manifest&& manifest,
Manifest::ManifestInstaller&& installer)
: PackageVersion(std::move(packageVersion)), InstalledPackageVersion(std::move(installedPackageVersion)), Manifest(std::move(manifest)), Installer(std::move(installer)) { }

std::shared_ptr<Repository::IPackageVersion> PackageVersion;
std::shared_ptr<Repository::IPackageVersion> InstalledPackageVersion;
Manifest::Manifest Manifest;
Manifest::ManifestInstaller Installer;
};
}

void ReportDependencies::operator()(Execution::Context& context) const
{
if (!Settings::ExperimentalFeature::IsEnabled(Settings::ExperimentalFeature::Feature::Dependencies))
{
return;
}
auto info = context.Reporter.Info();

const auto& dependencies = context.Get<Execution::Data::Dependencies>();
if (dependencies.HasAny())
{
Expand Down Expand Up @@ -114,7 +133,6 @@ namespace AppInstaller::CLI::Workflow
}
}


void ManagePackageDependencies::operator()(Execution::Context& context) const
{
if (!Settings::ExperimentalFeature::IsEnabled(Settings::ExperimentalFeature::Feature::Dependencies))
Expand All @@ -127,7 +145,7 @@ namespace AppInstaller::CLI::Workflow
const auto& rootManifest = context.Get<Execution::Data::Manifest>();

Dependency rootAsDependency = Dependency(DependencyType::Package, rootManifest.Id, rootManifest.Version);

const auto& rootInstaller = context.Get<Execution::Data::Installer>();
const auto& rootDependencies = rootInstaller->Dependencies;

Expand All @@ -146,25 +164,25 @@ namespace AppInstaller::CLI::Workflow
AICLI_TERMINATE_CONTEXT(APPINSTALLER_CLI_ERROR_INTERNAL_ERROR);
}


std::map<string_t, Execution::PackageToInstall> idToPackageMap;
std::map<string_t, DependencyPackageCandidate> idToPackageMap;
bool foundError = false;
DependencyGraph dependencyGraph(rootAsDependency, rootDependencies,
[&](Dependency node) {
[&](Dependency node)
{
DependencyNodeProcessor nodeProcessor(context);

auto result = nodeProcessor.EvaluateDependencies(node);
DependencyList list = nodeProcessor.GetDependencyList();
foundError = foundError || (result == DependencyNodeProcessorResult::Error);

if (result == DependencyNodeProcessorResult::Success)
{
Execution::PackageToInstall packageToInstall{
DependencyPackageCandidate dependencyPackageCandidate{
std::move(nodeProcessor.GetPackageLatestVersion()),
std::move(nodeProcessor.GetPackageInstalledVersion()),
std::move(nodeProcessor.GetManifest()),
std::move(nodeProcessor.GetPreferredInstaller()) };
idToPackageMap.emplace(node.Id, std::move(packageToInstall));
idToPackageMap.emplace(node.Id, std::move(dependencyPackageCandidate));
};

return list;
Expand All @@ -185,21 +203,43 @@ namespace AppInstaller::CLI::Workflow

const auto& installationOrder = dependencyGraph.GetInstallationOrder();

std::vector<Execution::PackageToInstall> installers;
std::vector<std::unique_ptr<Execution::Context>> dependencyPackageContexts;

for (auto const& node : installationOrder)
{
{
auto itr = idToPackageMap.find(node.Id);
// if the package was already installed (with a useful version) or is the root
// then there will be no installer for it on the map.
if (itr != idToPackageMap.end())
{
installers.push_back(std::move(itr->second));
auto dependencyContextPtr = context.CreateSubContext();
Execution::Context& dependencyContext = *dependencyContextPtr;
auto previousThreadGlobals = dependencyContext.SetForCurrentThread();

Logging::Telemetry().LogSelectedInstaller(
static_cast<int>(itr->second.Installer.Arch),
itr->second.Installer.Url,
Manifest::InstallerTypeToString(itr->second.Installer.InstallerType),
Manifest::ScopeToString(itr->second.Installer.Scope),
itr->second.Installer.Locale);

Logging::Telemetry().LogManifestFields(
itr->second.Manifest.Id,
itr->second.Manifest.DefaultLocalization.Get<Manifest::Localization::PackageName>(),
itr->second.Manifest.Version);

// Extract the data needed for installing
dependencyContext.Add<Execution::Data::PackageVersion>(itr->second.PackageVersion);
dependencyContext.Add<Execution::Data::Manifest>(itr->second.Manifest);
dependencyContext.Add<Execution::Data::InstalledPackageVersion>(itr->second.InstalledPackageVersion);
dependencyContext.Add<Execution::Data::Installer>(itr->second.Installer);

dependencyPackageContexts.emplace_back(std::move(dependencyContextPtr));
}
}

// Install dependencies in the correct order
context.Add<Execution::Data::PackagesToInstall>(installers);
context.Add<Execution::Data::PackagesToInstall>(std::move(dependencyPackageContexts));
context << Workflow::InstallMultiplePackages(m_dependencyReportMessage, APPINSTALLER_CLI_ERROR_INSTALL_DEPENDENCIES, {}, false, true);
}
}
4 changes: 2 additions & 2 deletions src/AppInstallerCLICore/Workflows/DependencyNodeProcessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ using namespace AppInstaller::Repository;

namespace AppInstaller::CLI::Workflow
{
DependencyNodeProcessor::DependencyNodeProcessor(Execution::Context& context)
: m_context(context) {}
DependencyNodeProcessor::DependencyNodeProcessor(Execution::Context& context)
: m_context(context) {}

DependencyNodeProcessorResult DependencyNodeProcessor::EvaluateDependencies(Dependency& dependencyNode)
{
Expand Down
Loading

0 comments on commit cc2dd14

Please sign in to comment.