commit 0699598f8d1ee7962284c52e4ab9b0ac4a5f1217
parent 21f3c96a23e6f2c1c9593237f8fe971549d74a6f
Author: JohnMcPMS <johnmcp@microsoft.com>
Date: Mon, 23 Mar 2020 15:53:33 -0700
Add telemetry for more scenarios (#67)
Diffstat:
12 files changed, 109 insertions(+), 60 deletions(-)
diff --git a/src/AppInstallerCLICore/Commands/HashCommand.cpp b/src/AppInstallerCLICore/Commands/HashCommand.cpp
@@ -34,7 +34,7 @@ namespace AppInstaller::CLI
void HashCommand::ExecuteInternal(Execution::Context& context) const
{
auto inputFile = context.Args.GetArg(Execution::Args::Type::HashFile);
- std::ifstream inStream{ *inputFile, std::ifstream::binary };
+ std::ifstream inStream{ inputFile, std::ifstream::binary };
context.Reporter.ShowMsg("File Hash: " + Utility::SHA256::ConvertToString(Utility::SHA256::ComputeHash(inStream)));
@@ -42,7 +42,7 @@ namespace AppInstaller::CLI
{
try
{
- Msix::MsixInfo msixInfo{ *inputFile };
+ Msix::MsixInfo msixInfo{ inputFile };
auto signature = msixInfo.GetSignature();
auto signatureHash = Utility::SHA256::ComputeHash(signature.data(), static_cast<uint32_t>(signature.size()));
diff --git a/src/AppInstallerCLICore/Commands/SourceCommand.cpp b/src/AppInstallerCLICore/Commands/SourceCommand.cpp
@@ -62,12 +62,12 @@ namespace AppInstaller::CLI
void SourceAddCommand::ExecuteInternal(Execution::Context& context) const
{
- std::string name = *context.Args.GetArg(Execution::Args::Type::SourceName);
- std::string arg = *context.Args.GetArg(Execution::Args::Type::SourceArg);
+ std::string name(context.Args.GetArg(Execution::Args::Type::SourceName));
+ std::string arg(context.Args.GetArg(Execution::Args::Type::SourceArg));
std::string type;
if (context.Args.Contains(Execution::Args::Type::SourceType))
{
- type = *context.Args.GetArg(Execution::Args::Type::SourceType);
+ type = context.Args.GetArg(Execution::Args::Type::SourceType);
}
context.Reporter.ShowMsg("Adding source:");
@@ -108,12 +108,12 @@ namespace AppInstaller::CLI
if (context.Args.Contains(Execution::Args::Type::SourceName))
{
- const std::string& name = *context.Args.GetArg(Execution::Args::Type::SourceName);
+ auto name = context.Args.GetArg(Execution::Args::Type::SourceName);
auto itr = std::find_if(sources.begin(), sources.end(), [name](const Repository::SourceDetails& sd) { return Utility::CaseInsensitiveEquals(sd.Name, name); });
if (itr == sources.end())
{
- context.Reporter.ShowMsg("No source with the given name was found: " + name);
+ context.Reporter.Info() << "No source with the given name was found: " << name << std::endl;
}
else
{
@@ -174,8 +174,8 @@ namespace AppInstaller::CLI
{
if (context.Args.Contains(Execution::Args::Type::SourceName))
{
- const std::string& name = *context.Args.GetArg(Execution::Args::Type::SourceName);
- context.Reporter.ShowMsg("Updating source: " + name + "...");
+ auto name = context.Args.GetArg(Execution::Args::Type::SourceName);
+ context.Reporter.Info() << "Updating source: " << name << "..." << std::endl;
if (!context.Reporter.ExecuteWithProgress(std::bind(Repository::UpdateSource, name, std::placeholders::_1)))
{
context.Reporter.EmptyLine();
@@ -221,8 +221,8 @@ namespace AppInstaller::CLI
void SourceRemoveCommand::ExecuteInternal(Execution::Context& context) const
{
- const std::string& name = *context.Args.GetArg(Execution::Args::Type::SourceName);
- context.Reporter.ShowMsg("Removing source: " + name + "...");
+ auto name = context.Args.GetArg(Execution::Args::Type::SourceName);
+ context.Reporter.Info() << "Removing source: " << name << "..." << std::endl;
if (!context.Reporter.ExecuteWithProgress(std::bind(Repository::RemoveSource, name, std::placeholders::_1)))
{
context.Reporter.ShowMsg("Could not find a source by that name.", Execution::Reporter::Level::Warning);
diff --git a/src/AppInstallerCLICore/Core.cpp b/src/AppInstallerCLICore/Core.cpp
@@ -86,6 +86,7 @@ namespace AppInstaller::CLI
commandToExecute = foundCommand.get();
}
+ // TODO: Log full command (so source::add) rather than just leaf command
Logging::Telemetry().LogCommand(commandToExecute->Name());
commandToExecute->ParseArguments(invocation, context.Args);
diff --git a/src/AppInstallerCLICore/ExecutionArgs.h b/src/AppInstallerCLICore/ExecutionArgs.h
@@ -2,6 +2,7 @@
// Licensed under the MIT License.
#pragma once
#include <string>
+#include <string_view>
#include <map>
#include <vector>
@@ -59,16 +60,16 @@ namespace AppInstaller::CLI::Execution
return (itr == m_parsedArgs.end() ? nullptr : &(itr->second));
}
- const std::string* GetArg(Type arg) const
+ std::string_view GetArg(Type arg) const
{
auto itr = m_parsedArgs.find(arg);
if (itr == m_parsedArgs.end())
{
- return nullptr;
+ return {};
}
- return &(itr->second[0]);
+ return itr->second[0];
}
size_t GetCount(Type arg) const
diff --git a/src/AppInstallerCLICore/Workflows/InstallFlow.cpp b/src/AppInstallerCLICore/Workflows/InstallFlow.cpp
@@ -16,7 +16,8 @@ namespace AppInstaller::Workflow
{
if (m_argsRef.Contains(Execution::Args::Type::Manifest))
{
- m_manifest = Manifest::Manifest::CreateFromPath(*(m_argsRef.GetArg(Execution::Args::Type::Manifest)));
+ m_manifest = Manifest::Manifest::CreateFromPath(m_argsRef.GetArg(Execution::Args::Type::Manifest));
+ Logging::Telemetry().LogManifestFields(m_manifest.Id, m_manifest.Name, m_manifest.Version);
}
else
{
@@ -33,8 +34,6 @@ namespace AppInstaller::Workflow
void InstallFlow::InstallInternal()
{
- Logging::Telemetry().LogManifestFields(m_manifest.Name, m_manifest.Version);
-
auto installerHandler = GetInstallerHandler();
installerHandler->Download();
diff --git a/src/AppInstallerCLICore/Workflows/ShellExecuteInstallerHandler.cpp b/src/AppInstallerCLICore/Workflows/ShellExecuteInstallerHandler.cpp
@@ -145,7 +145,7 @@ namespace AppInstaller::Workflow
std::string logPath;
if (m_argsRef.Contains(Execution::Args::Type::Log))
{
- logPath = *m_argsRef.GetArg(Execution::Args::Type::Log);
+ logPath = m_argsRef.GetArg(Execution::Args::Type::Log);
}
else
{
@@ -156,7 +156,7 @@ namespace AppInstaller::Workflow
// Populate <InstallPath> with value from command line.
if (m_argsRef.Contains(Execution::Args::Type::InstallLocation))
{
- Utility::FindAndReplace(installerArgs, std::string(ARG_TOKEN_INSTALLPATH), *m_argsRef.GetArg(Execution::Args::Type::InstallLocation));
+ Utility::FindAndReplace(installerArgs, std::string(ARG_TOKEN_INSTALLPATH), m_argsRef.GetArg(Execution::Args::Type::InstallLocation));
}
// Todo: language token support will be implemented later
@@ -167,7 +167,7 @@ namespace AppInstaller::Workflow
// If override switch is specified, use the override value as installer args.
if (m_argsRef.Contains(Execution::Args::Type::Override))
{
- return *m_argsRef.GetArg(Execution::Args::Type::Override);
+ return std::string{ m_argsRef.GetArg(Execution::Args::Type::Override) };
}
std::string installerArgs = GetInstallerArgsTemplate();
diff --git a/src/AppInstallerCLICore/Workflows/WorkflowBase.cpp b/src/AppInstallerCLICore/Workflows/WorkflowBase.cpp
@@ -14,7 +14,7 @@ namespace AppInstaller::Workflow
std::string sourceName;
if (m_argsRef.Contains(Execution::Args::Type::Source))
{
- sourceName = *m_argsRef.GetArg(Execution::Args::Type::Source);
+ sourceName = m_argsRef.GetArg(Execution::Args::Type::Source);
}
m_source = m_reporterRef.ExecuteWithProgress(std::bind(OpenSource, sourceName, std::placeholders::_1));
@@ -35,8 +35,7 @@ namespace AppInstaller::Workflow
{
noSources = false;
- m_reporterRef.ShowMsg("No sources match the given value '" + *m_argsRef.GetArg(Execution::Args::Type::Source) + "'",
- Execution::Reporter::Level::Warning);
+ m_reporterRef.Warn() << "No sources match the given value '" << m_argsRef.GetArg(Execution::Args::Type::Source) << "'" << std::endl;
m_reporterRef.ShowMsg("The configured sources are:");
for (const auto& details : sources)
{
@@ -64,39 +63,48 @@ namespace AppInstaller::Workflow
SearchRequest searchRequest;
if (m_argsRef.Contains(Execution::Args::Type::Query))
{
- searchRequest.Query.emplace(RequestMatch(matchType, *m_argsRef.GetArg(Execution::Args::Type::Query)));
+ searchRequest.Query.emplace(RequestMatch(matchType, m_argsRef.GetArg(Execution::Args::Type::Query)));
}
if (m_argsRef.Contains(Execution::Args::Type::Id))
{
- searchRequest.Filters.emplace_back(ApplicationMatchFilter(ApplicationMatchField::Id, matchType, *m_argsRef.GetArg(Execution::Args::Type::Id)));
+ searchRequest.Filters.emplace_back(ApplicationMatchFilter(ApplicationMatchField::Id, matchType, m_argsRef.GetArg(Execution::Args::Type::Id)));
}
if (m_argsRef.Contains(Execution::Args::Type::Name))
{
- searchRequest.Filters.emplace_back(ApplicationMatchFilter(ApplicationMatchField::Name, matchType, *m_argsRef.GetArg(Execution::Args::Type::Name)));
+ searchRequest.Filters.emplace_back(ApplicationMatchFilter(ApplicationMatchField::Name, matchType, m_argsRef.GetArg(Execution::Args::Type::Name)));
}
if (m_argsRef.Contains(Execution::Args::Type::Moniker))
{
- searchRequest.Filters.emplace_back(ApplicationMatchFilter(ApplicationMatchField::Moniker, matchType, *m_argsRef.GetArg(Execution::Args::Type::Moniker)));
+ searchRequest.Filters.emplace_back(ApplicationMatchFilter(ApplicationMatchField::Moniker, matchType, m_argsRef.GetArg(Execution::Args::Type::Moniker)));
}
if (m_argsRef.Contains(Execution::Args::Type::Tag))
{
- searchRequest.Filters.emplace_back(ApplicationMatchFilter(ApplicationMatchField::Tag, matchType, *m_argsRef.GetArg(Execution::Args::Type::Tag)));
+ searchRequest.Filters.emplace_back(ApplicationMatchFilter(ApplicationMatchField::Tag, matchType, m_argsRef.GetArg(Execution::Args::Type::Tag)));
}
if (m_argsRef.Contains(Execution::Args::Type::Command))
{
- searchRequest.Filters.emplace_back(ApplicationMatchFilter(ApplicationMatchField::Command, matchType, *m_argsRef.GetArg(Execution::Args::Type::Command)));
+ searchRequest.Filters.emplace_back(ApplicationMatchFilter(ApplicationMatchField::Command, matchType, m_argsRef.GetArg(Execution::Args::Type::Command)));
}
if (m_argsRef.Contains(Execution::Args::Type::Count))
{
- searchRequest.MaximumResults = std::stoi(*m_argsRef.GetArg(Execution::Args::Type::Count));
+ searchRequest.MaximumResults = std::stoi(std::string(m_argsRef.GetArg(Execution::Args::Type::Count)));
}
+ Logging::Telemetry().LogSearchRequest(
+ m_argsRef.GetArg(Execution::Args::Type::Query),
+ m_argsRef.GetArg(Execution::Args::Type::Id),
+ m_argsRef.GetArg(Execution::Args::Type::Name),
+ m_argsRef.GetArg(Execution::Args::Type::Moniker),
+ m_argsRef.GetArg(Execution::Args::Type::Tag),
+ m_argsRef.GetArg(Execution::Args::Type::Command),
+ searchRequest.MaximumResults,
+ searchRequest.ToString());
m_searchResult = m_source->Search(searchRequest);
return true;
@@ -149,10 +157,8 @@ namespace AppInstaller::Workflow
{
auto app = m_searchResult.Matches.at(0).Application.get();
- Logging::Telemetry().LogManifestFields(app->GetName(), app->GetId());
-
- std::string_view version = (m_argsRef.Contains(Execution::Args::Type::Version) ? *m_argsRef.GetArg(Execution::Args::Type::Version) : std::string_view{});
- std::string_view channel = (m_argsRef.Contains(Execution::Args::Type::Channel) ? *m_argsRef.GetArg(Execution::Args::Type::Channel) : std::string_view{});
+ std::string_view version = m_argsRef.GetArg(Execution::Args::Type::Version);
+ std::string_view channel = m_argsRef.GetArg(Execution::Args::Type::Channel);
std::optional<Manifest::Manifest> manifest = app->GetManifest(version, channel);
@@ -175,6 +181,7 @@ namespace AppInstaller::Workflow
}
m_manifest = std::move(manifest.value());
+ Logging::Telemetry().LogManifestFields(m_manifest.Id, m_manifest.Name, m_manifest.Version);
return true;
}
diff --git a/src/AppInstallerCommonCore/AppInstallerStrings.cpp b/src/AppInstallerCommonCore/AppInstallerStrings.cpp
@@ -123,7 +123,7 @@ namespace AppInstaller::Utility
return nonWhitespaceNotFound;
}
- void FindAndReplace(std::string& inputStr, const std::string& token, const std::string& value)
+ void FindAndReplace(std::string& inputStr, std::string_view token, std::string_view value)
{
std::string::size_type pos = 0u;
while ((pos = inputStr.find(token, pos)) != std::string::npos)
diff --git a/src/AppInstallerCommonCore/AppInstallerTelemetry.cpp b/src/AppInstallerCommonCore/AppInstallerTelemetry.cpp
@@ -7,6 +7,8 @@
#include "Public/AppInstallerRuntime.h"
#include "Public/AppInstallerStrings.h"
+#define AICLI_TraceLoggingStringView(_sv_,_name_) TraceLoggingCountedString(_sv_.data(), static_cast<ULONG>(_sv_.size()), _name_)
+
// Helper to print a GUID
std::ostream& operator<<(std::ostream& out, const GUID& guid)
{
@@ -117,7 +119,7 @@ namespace AppInstaller::Logging
"CommandFound",
GetActivityId(),
nullptr,
- TraceLoggingCountedString(commandName.data(), static_cast<ULONG>(commandName.size()), "Command"),
+ AICLI_TraceLoggingStringView(commandName, "Command"),
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance),
TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA));
}
@@ -133,7 +135,7 @@ namespace AppInstaller::Logging
"CommandSuccess",
GetActivityId(),
nullptr,
- TraceLoggingCountedString(commandName.data(), static_cast<ULONG>(commandName.size()), "Command"),
+ AICLI_TraceLoggingStringView(commandName, "Command"),
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance),
TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA));
}
@@ -141,7 +143,7 @@ namespace AppInstaller::Logging
AICLI_LOG(CLI, Info, << "Leaf command succeeded: " << commandName);
}
- void TelemetryTraceLogger::LogManifestFields(const std::string& name, const std::string& version) noexcept
+ void TelemetryTraceLogger::LogManifestFields(std::string_view id, std::string_view name, std::string_view version) noexcept
{
if (g_IsTelemetryProviderEnabled)
{
@@ -149,8 +151,9 @@ namespace AppInstaller::Logging
"ManifestFields",
GetActivityId(),
nullptr,
- TraceLoggingCountedString(name.c_str(), static_cast<ULONG>(name.size()),"Name"),
- TraceLoggingCountedString(version.c_str(), static_cast<ULONG>(version.size()), "Version"),
+ AICLI_TraceLoggingStringView(id, "Id"),
+ AICLI_TraceLoggingStringView(name,"Name"),
+ AICLI_TraceLoggingStringView(version, "Version"),
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance|PDT_ProductAndServiceUsage),
TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA));
}
@@ -188,7 +191,7 @@ namespace AppInstaller::Logging
AICLI_LOG(CLI, Info, << "Multiple apps found matching input criteria");
}
- void TelemetryTraceLogger::LogAppFound(const std::string& name, const std::string& id) noexcept
+ void TelemetryTraceLogger::LogAppFound(std::string_view name, std::string_view id) noexcept
{
if (g_IsTelemetryProviderEnabled)
{
@@ -196,8 +199,8 @@ namespace AppInstaller::Logging
"AppFound",
GetActivityId(),
nullptr,
- TraceLoggingCountedString(name.c_str(), static_cast<ULONG>(name.size()), "AppName"),
- TraceLoggingCountedString(id.c_str(), static_cast<ULONG>(id.size()), "id"),
+ AICLI_TraceLoggingStringView(name, "AppName"),
+ AICLI_TraceLoggingStringView(id, "id"),
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance | PDT_ProductAndServiceUsage),
TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA));
}
@@ -205,7 +208,7 @@ namespace AppInstaller::Logging
AICLI_LOG(CLI, Info, << "Found one app. App id: " << id << " App name: " << name);
}
- void TelemetryTraceLogger::LogSelectedInstaller(int arch, const std::string& url, const std::string& installerType, const std::string& scope, const std::string& language) noexcept
+ void TelemetryTraceLogger::LogSelectedInstaller(int arch, std::string_view url, std::string_view installerType, std::string_view scope, std::string_view language) noexcept
{
if (g_IsTelemetryProviderEnabled)
{
@@ -214,10 +217,10 @@ namespace AppInstaller::Logging
GetActivityId(),
nullptr,
TraceLoggingInt32(arch, "Arch"),
- TraceLoggingCountedString(url.c_str(), static_cast<ULONG>(url.size()), "URL"),
- TraceLoggingCountedString(installerType.c_str(), static_cast<ULONG>(installerType.size()), "InstallerType"),
- TraceLoggingCountedString(scope.c_str(), static_cast<ULONG>(scope.size()), "Scope"),
- TraceLoggingCountedString(language.c_str(), static_cast<ULONG>(language.size()), "Language"),
+ AICLI_TraceLoggingStringView(url, "URL"),
+ AICLI_TraceLoggingStringView(installerType, "InstallerType"),
+ AICLI_TraceLoggingStringView(scope, "Scope"),
+ AICLI_TraceLoggingStringView(language, "Language"),
TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance | PDT_ProductAndServiceUsage),
TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA));
}
@@ -228,7 +231,35 @@ namespace AppInstaller::Logging
AICLI_LOG(CLI, Verbose, << "Selected installer InstallerType: " << installerType);
AICLI_LOG(CLI, Verbose, << "Selected installer scope: " << scope);
AICLI_LOG(CLI, Verbose, << "Selected installer language: " << language);
+ }
+ void TelemetryTraceLogger::LogSearchRequest(
+ std::string_view query,
+ std::string_view id,
+ std::string_view name,
+ std::string_view moniker,
+ std::string_view tag,
+ std::string_view command,
+ size_t maximum,
+ std::string_view request)
+ {
+ if (g_IsTelemetryProviderEnabled)
+ {
+ TraceLoggingWriteActivity(g_hTelemetryProvider,
+ "SearchRequest",
+ GetActivityId(),
+ nullptr,
+ AICLI_TraceLoggingStringView(query, "Query"),
+ AICLI_TraceLoggingStringView(id, "Id"),
+ AICLI_TraceLoggingStringView(name, "Name"),
+ AICLI_TraceLoggingStringView(moniker, "Moniker"),
+ AICLI_TraceLoggingStringView(tag, "Tag"),
+ AICLI_TraceLoggingStringView(command, "Command"),
+ TraceLoggingUInt64(static_cast<UINT64>(maximum), "Maximum"),
+ AICLI_TraceLoggingStringView(request, "Request"),
+ TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance | PDT_ProductAndServiceUsage),
+ TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA));
+ }
}
void TelemetryTraceLogger::LogSearchResultCount(uint64_t resultCount) noexcept
diff --git a/src/AppInstallerCommonCore/Public/AppInstallerStrings.h b/src/AppInstallerCommonCore/Public/AppInstallerStrings.h
@@ -83,7 +83,7 @@ namespace AppInstaller::Utility
bool IsEmptyOrWhitespace(std::wstring_view str);
// Find token in the input string and replace with value.
- void FindAndReplace(std::string& inputStr, const std::string& token, const std::string& value);
+ void FindAndReplace(std::string& inputStr, std::string_view token, std::string_view value);
// Reads the entire stream into a string.
std::string ReadEntireStream(std::istream& stream);
diff --git a/src/AppInstallerCommonCore/Public/AppInstallerTelemetry.h b/src/AppInstallerCommonCore/Public/AppInstallerTelemetry.h
@@ -1,7 +1,6 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#pragma once
-
#include <wil/result_macros.h>
#include <string_view>
@@ -38,21 +37,32 @@ namespace AppInstaller::Logging
void LogCommandSuccess(std::string_view commandName) noexcept;
// Logs the Manifest fields.
- void LogManifestFields(const std::string& name, const std::string& version) noexcept;
+ void LogManifestFields(std::string_view id, std::string_view name, std::string_view version) noexcept;
- //Logs when there is no matching App found for search
+ // Logs when there is no matching App found for search
void LogNoAppMatch() noexcept;
- //Logs when there is multiple matching Apps found for search
+ // Logs when there is multiple matching Apps found for search
void LogMultiAppMatch() noexcept;
- //Logs the name and Id of app found
- void LogAppFound(const std::string& name, const std::string& id) noexcept;
+ // Logs the name and Id of app found
+ void LogAppFound(std::string_view name, std::string_view id) noexcept;
+
+ // Logs the selected installer details
+ void LogSelectedInstaller(int arch, std::string_view url, std::string_view installerType, std::string_view scope, std::string_view language) noexcept;
- //Logs the selected installer details
- void LogSelectedInstaller(int arch, const std::string& url, const std::string& installerType, const std::string& scope, const std::string& language) noexcept;
+ // Logs details of a search request.
+ void LogSearchRequest(
+ std::string_view query,
+ std::string_view id,
+ std::string_view name,
+ std::string_view moniker,
+ std::string_view tag,
+ std::string_view command,
+ size_t maximum,
+ std::string_view request);
- //Logs the Search Result
+ // Logs the Search Result
void LogSearchResultCount(uint64_t resultCount) noexcept;
private:
diff --git a/src/AppInstallerRepositoryCore/Public/AppInstallerRepositorySearch.h b/src/AppInstallerRepositoryCore/Public/AppInstallerRepositorySearch.h
@@ -40,7 +40,7 @@ namespace AppInstaller::Repository
MatchType Type;
Utility::NormalizedString Value;
- RequestMatch(MatchType t, const std::string& v) : Type(t), Value(v) {}
+ RequestMatch(MatchType t, std::string_view v) : Type(t), Value(v) {}
};
// A match on a specific field to be performed during a search.
@@ -48,7 +48,7 @@ namespace AppInstaller::Repository
{
ApplicationMatchField Field;
- ApplicationMatchFilter(ApplicationMatchField f, MatchType t, const std::string& v) : RequestMatch(t, v), Field(f) {}
+ ApplicationMatchFilter(ApplicationMatchField f, MatchType t, std::string_view v) : RequestMatch(t, v), Field(f) {}
};
// Container for data used to filter the available manifests in a source.