winget-cli

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

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:
Msrc/AppInstallerCLICore/Commands/HashCommand.cpp | 4++--
Msrc/AppInstallerCLICore/Commands/SourceCommand.cpp | 18+++++++++---------
Msrc/AppInstallerCLICore/Core.cpp | 1+
Msrc/AppInstallerCLICore/ExecutionArgs.h | 7++++---
Msrc/AppInstallerCLICore/Workflows/InstallFlow.cpp | 5++---
Msrc/AppInstallerCLICore/Workflows/ShellExecuteInstallerHandler.cpp | 6+++---
Msrc/AppInstallerCLICore/Workflows/WorkflowBase.cpp | 35+++++++++++++++++++++--------------
Msrc/AppInstallerCommonCore/AppInstallerStrings.cpp | 2+-
Msrc/AppInstallerCommonCore/AppInstallerTelemetry.cpp | 57++++++++++++++++++++++++++++++++++++++++++++-------------
Msrc/AppInstallerCommonCore/Public/AppInstallerStrings.h | 2+-
Msrc/AppInstallerCommonCore/Public/AppInstallerTelemetry.h | 28+++++++++++++++++++---------
Msrc/AppInstallerRepositoryCore/Public/AppInstallerRepositorySearch.h | 4++--
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.