[vcpkg metrics] Allow someone to opt out after build (#11542)

* [vcpkg metrics] start using json library

Additionally, add floats to the JSON library since they're required.

* [vcpkg metrics] allow users to disable metrics after the build

Additionally, as a drive by, fix UUID generation

* fix metrics data

* code review
This commit is contained in:
nicole mazzuca 2020-05-29 14:09:03 -07:00 committed by GitHub
parent a64dc07690
commit 09319cd79e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 644 additions and 356 deletions

View File

@ -80,6 +80,10 @@ Code licensed under the [MIT License](LICENSE.txt).
## Telemetry
vcpkg collects usage data in order to help us improve your experience. The data collected by Microsoft is anonymous. You can opt-out of telemetry by running `bootstrap-vcpkg.bat` or `bootstrap-vcpkg.sh` with `-disableMetrics`.
vcpkg collects usage data in order to help us improve your experience.
The data collected by Microsoft is anonymous.
You can opt-out of telemetry by re-running the bootstrap-vcpkg script with -disableMetrics,
passing --disable-metrics to vcpkg on the command line,
or by setting the VCPKG_DISABLE_METRICS environment variable.
Read more about vcpkg telemetry at docs/about/privacy.md

View File

@ -1,7 +1,7 @@
# Vcpkg telemetry and privacy
vcpkg collects telemetry data to understand usage issues, such as failing packages, and to guide tool improvements. The collected data is anonymous.
For more information about how Microsoft protects your privacy, see https://privacy.microsoft.com/en-US/privacystatement#mainenterprisedeveloperproductsmodule
For more information about how Microsoft protects your privacy, see https://privacy.microsoft.com/en-US/privacystatement#mainenterprisedeveloperproductsmodule
## Scope
@ -22,7 +22,11 @@ vcpkg displays text similar to the following when you build vcpkg. This is how M
```
Telemetry
---------
vcpkg collects usage data in order to help us improve your experience. The data collected by Microsoft is anonymous. You can opt-out of telemetry by re-running the bootstrap-vcpkg script with -disableMetrics.
vcpkg collects usage data in order to help us improve your experience.
The data collected by Microsoft is anonymous.
You can opt-out of telemetry by re-running the bootstrap-vcpkg script with -disableMetrics,
passing --disable-metrics to vcpkg on the command line,
or by setting the VCPKG_DISABLE_METRICS environment variable.
Read more about vcpkg telemetry at docs/about/privacy.md
```
@ -39,7 +43,7 @@ You can see the telemetry events any command by appending `--printmetrics` after
In the source code (included in `toolsrc\`), you can search for calls to the functions `track_property()` and `track_metric()` to see every specific data point we collect.
## Avoid inadvertent disclosure information
## Avoid inadvertent disclosure information
vcpkg contributors and anyone else running a version of vcpkg that they built themselves should consider the path to their source code. If a crash occurs when using vcpkg, the file path from the build machine is collected as part of the stack trace and isn't hashed.
Because of this, builds of vcpkg shouldn't be located in directories whose path names expose personal or sensitive information.

View File

@ -341,7 +341,7 @@ if ($disableMetrics)
$platform = "x86"
$vcpkgReleaseDir = "$vcpkgSourcesPath\msbuild.x86.release"
if($PSVersionTable.PSVersion.Major -le 2)
{
{
$architecture=(Get-WmiObject win32_operatingsystem | Select-Object osarchitecture).osarchitecture
}
else
@ -417,9 +417,13 @@ if (-not $disableMetrics)
Write-Host @"
Telemetry
---------
vcpkg collects usage data in order to help us improve your experience. The data collected by Microsoft is anonymous. You can opt-out of telemetry by re-running bootstrap-vcpkg.bat with -disableMetrics.
Read more about vcpkg telemetry at docs/about/privacy.md
vcpkg collects usage data in order to help us improve your experience.
The data collected by Microsoft is anonymous.
You can opt-out of telemetry by re-running the bootstrap-vcpkg script with -disableMetrics,
passing --disable-metrics to vcpkg on the command line,
or by setting the VCPKG_DISABLE_METRICS environment variable.
Read more about vcpkg telemetry at docs/about/privacy.md
"@
}

View File

@ -256,9 +256,15 @@ rm -rf "$vcpkgRootDir/vcpkg"
cp "$buildDir/vcpkg" "$vcpkgRootDir/"
if ! [ "$vcpkgDisableMetrics" = "ON" ]; then
echo "Telemetry"
echo "---------"
echo "vcpkg collects usage data in order to help us improve your experience. The data collected by Microsoft is anonymous. You can opt-out of telemetry by re-running bootstrap-vcpkg.sh with -disableMetrics"
echo "Read more about vcpkg telemetry at docs/about/privacy.md"
echo ""
cat <<EOF
Telemetry
---------
vcpkg collects usage data in order to help us improve your experience.
The data collected by Microsoft is anonymous.
You can opt-out of telemetry by re-running the bootstrap-vcpkg script with -disableMetrics,
passing --disable-metrics to vcpkg on the command line,
or by setting the VCPKG_DISABLE_METRICS environment variable.
Read more about vcpkg telemetry at docs/about/privacy.md
EOF
fi

View File

@ -32,3 +32,6 @@ ForEachMacros: [TEST_CASE, SECTION]
PenaltyReturnTypeOnItsOwnLine: 1000
SpaceAfterTemplateKeyword: false
SpaceBeforeCpp11BracedList: false
IncludeBlocks: Preserve
SortIncludes: false

View File

@ -9,6 +9,12 @@
#include <winhttp.h>
#endif
#include <math.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <algorithm>
#include <array>
#include <atomic>
@ -16,10 +22,6 @@
#include <cctype>
#include <chrono>
#include <codecvt>
#include <cstdarg>
#include <cstddef>
#include <cstdint>
#include <cstring>
#if VCPKG_USE_STD_FILESYSTEM
#include <filesystem>

View File

@ -70,6 +70,7 @@ namespace vcpkg::Json
{
Null,
Boolean,
Integer,
Number,
String,
Array,
@ -84,10 +85,19 @@ namespace vcpkg::Json
struct Value
{
Value() noexcept; // equivalent to Value::null()
Value(Value&&) noexcept;
Value& operator=(Value&&) noexcept;
~Value();
Value clone() const noexcept;
ValueKind kind() const noexcept;
bool is_null() const noexcept;
bool is_boolean() const noexcept;
bool is_integer() const noexcept;
// either integer _or_ number
bool is_number() const noexcept;
bool is_string() const noexcept;
bool is_array() const noexcept;
@ -95,7 +105,8 @@ namespace vcpkg::Json
// a.x() asserts when !a.is_x()
bool boolean() const noexcept;
int64_t number() const noexcept;
int64_t integer() const noexcept;
double number() const noexcept;
StringView string() const noexcept;
const Array& array() const noexcept;
@ -104,18 +115,13 @@ namespace vcpkg::Json
const Object& object() const noexcept;
Object& object() noexcept;
Value(Value&&) noexcept;
Value& operator=(Value&&) noexcept;
~Value();
Value() noexcept; // equivalent to Value::null()
static Value null(std::nullptr_t) noexcept;
static Value boolean(bool) noexcept;
static Value number(int64_t i) noexcept;
static Value integer(int64_t i) noexcept;
static Value number(double d) noexcept;
static Value string(StringView) noexcept;
static Value array(Array&&) noexcept;
static Value object(Object&&) noexcept;
Value clone() const noexcept;
private:
friend struct impl::ValueImpl;
@ -128,11 +134,24 @@ namespace vcpkg::Json
using underlying_t = std::vector<Value>;
public:
Array() = default;
Array(Array const&) = delete;
Array(Array&&) = default;
Array& operator=(Array const&) = delete;
Array& operator=(Array&&) = default;
~Array() = default;
Array clone() const noexcept;
using iterator = underlying_t::iterator;
using const_iterator = underlying_t::const_iterator;
void push_back(Value&& value) { this->underlying_.push_back(std::move(value)); }
void insert_before(iterator it, Value&& value) { this->underlying_.insert(it, std::move(value)); }
Value& push_back(Value&& value);
Object& push_back(Object&& value);
Array& push_back(Array&& value);
Value& insert_before(iterator it, Value&& value);
Object& insert_before(iterator it, Object&& value);
Array& insert_before(iterator it, Array&& value);
std::size_t size() const noexcept { return this->underlying_.size(); }
@ -148,8 +167,6 @@ namespace vcpkg::Json
return this->underlying_[idx];
}
Array clone() const noexcept;
iterator begin() { return underlying_.begin(); }
iterator end() { return underlying_.end(); }
const_iterator begin() const { return cbegin(); }
@ -160,7 +177,6 @@ namespace vcpkg::Json
private:
underlying_t underlying_;
};
struct Object
{
private:
@ -169,12 +185,26 @@ namespace vcpkg::Json
underlying_t::const_iterator internal_find_key(StringView key) const noexcept;
public:
// these are here for better diagnostics
Object() = default;
Object(Object const&) = delete;
Object(Object&&) = default;
Object& operator=(Object const&) = delete;
Object& operator=(Object&&) = default;
~Object() = default;
Object clone() const noexcept;
// asserts if the key is found
void insert(std::string key, Value value) noexcept;
Value& insert(std::string key, Value&& value);
Object& insert(std::string key, Object&& value);
Array& insert(std::string key, Array&& value);
// replaces the value if the key is found, otherwise inserts a new
// value.
void insert_or_replace(std::string key, Value value) noexcept;
Value& insert_or_replace(std::string key, Value&& value);
Object& insert_or_replace(std::string key, Object&& value);
Array& insert_or_replace(std::string key, Array&& value);
// returns whether the key existed
bool remove(StringView key) noexcept;
@ -200,8 +230,6 @@ namespace vcpkg::Json
std::size_t size() const noexcept { return this->underlying_.size(); }
Object clone() const noexcept;
struct const_iterator
{
using value_type = std::pair<StringView, const Value&>;
@ -245,6 +273,9 @@ namespace vcpkg::Json
const Files::Filesystem&, const fs::path&, std::error_code& ec) noexcept;
ExpectedT<std::pair<Value, JsonStyle>, std::unique_ptr<Parse::IParseError>> parse(
StringView text, const fs::path& filepath = "") noexcept;
std::string stringify(const Value&, JsonStyle style) noexcept;
std::string stringify(const Value&, JsonStyle style);
std::string stringify(const Object&, JsonStyle style);
std::string stringify(const Array&, JsonStyle style);
}

View File

@ -10,6 +10,7 @@ namespace vcpkg::Metrics
{
void set_send_metrics(bool should_send_metrics);
void set_print_metrics(bool should_print_metrics);
void set_disabled(bool disabled);
void set_user_information(const std::string& user_id, const std::string& first_use_time);
static void init_user_information(std::string& user_id, std::string& first_use_time);
@ -17,6 +18,8 @@ namespace vcpkg::Metrics
void track_buildtime(const std::string& name, double value);
void track_property(const std::string& name, const std::string& value);
bool metrics_enabled();
void upload(const std::string& payload);
void flush();
};
@ -24,5 +27,4 @@ namespace vcpkg::Metrics
extern Util::LockGuarded<Metrics> g_metrics;
std::string get_MAC_user();
bool get_compiled_metrics_enabled();
}

View File

@ -94,6 +94,8 @@ namespace vcpkg
std::vector<std::string> binarysources;
Optional<bool> debug = nullopt;
Optional<bool> sendmetrics = nullopt;
// fully disable metrics -- both printing and sending
Optional<bool> disable_metrics = nullopt;
Optional<bool> printmetrics = nullopt;
// feature flags

View File

@ -4,6 +4,8 @@
#include <vcpkg/base/json.h>
#include <vcpkg/base/unicode.h>
#include "math.h"
// TODO: remove this once we switch to C++20 completely
// This is the worst, but we also can't really deal with it any other way.
#if __cpp_char8_t
@ -57,9 +59,7 @@ TEST_CASE ("JSON parse strings", "[json]")
REQUIRE(res.get()->first.is_string());
REQUIRE(res.get()->first.string() == "\xED\xA0\x80");
const auto make_json_string = [] (vcpkg::StringView sv) {
return '"' + sv.to_string() + '"';
};
const auto make_json_string = [](vcpkg::StringView sv) { return '"' + sv.to_string() + '"'; };
const vcpkg::StringView radical = U8_STR("");
const vcpkg::StringView grin = U8_STR("😁");
@ -79,28 +79,51 @@ TEST_CASE ("JSON parse strings", "[json]")
REQUIRE(res.get()->first.string() == grin);
}
TEST_CASE ("JSON parse numbers", "[json]")
TEST_CASE ("JSON parse integers", "[json]")
{
auto res = Json::parse("0");
REQUIRE(res);
REQUIRE(res.get()->first.is_number());
REQUIRE(res.get()->first.number() == 0);
REQUIRE(res.get()->first.is_integer());
REQUIRE(res.get()->first.integer() == 0);
res = Json::parse("12345");
REQUIRE(res);
REQUIRE(res.get()->first.is_number());
REQUIRE(res.get()->first.number() == 12345);
REQUIRE(res.get()->first.is_integer());
REQUIRE(res.get()->first.integer() == 12345);
res = Json::parse("-12345");
REQUIRE(res);
REQUIRE(res.get()->first.is_number());
REQUIRE(res.get()->first.number() == -12345);
REQUIRE(res.get()->first.is_integer());
REQUIRE(res.get()->first.integer() == -12345);
res = Json::parse("9223372036854775807"); // INT64_MAX
REQUIRE(res);
REQUIRE(res.get()->first.is_number());
REQUIRE(res.get()->first.number() == 9223372036854775807);
REQUIRE(res.get()->first.is_integer());
REQUIRE(res.get()->first.integer() == 9223372036854775807);
res = Json::parse("-9223372036854775808");
REQUIRE(res);
REQUIRE(res.get()->first.is_integer());
REQUIRE(res.get()->first.integer() == (-9223372036854775807 - 1)); // INT64_MIN (C++'s parser is fun)
}
TEST_CASE ("JSON parse floats", "[json]")
{
auto res = Json::parse("0.0");
REQUIRE(res);
REQUIRE(res.get()->first.is_number());
REQUIRE(res.get()->first.number() == (-9223372036854775807 - 1)); // INT64_MIN (C++'s parser is fun)
REQUIRE(!res.get()->first.is_integer());
REQUIRE(res.get()->first.number() == 0.0);
REQUIRE(!signbit(res.get()->first.number()));
res = Json::parse("-0.0");
REQUIRE(res);
REQUIRE(res.get()->first.is_number());
REQUIRE(res.get()->first.number() == 0.0);
REQUIRE(signbit(res.get()->first.number()));
res = Json::parse("12345.6789");
REQUIRE(res);
REQUIRE(res.get()->first.is_number());
REQUIRE_THAT(res.get()->first.number(), Catch::WithinULP(12345.6789, 3));
res = Json::parse("-12345.6789");
REQUIRE(res);
REQUIRE(res.get()->first.is_number());
REQUIRE_THAT(res.get()->first.number(), Catch::WithinULP(-12345.6789, 3));
}
TEST_CASE ("JSON parse arrays", "[json]")
@ -116,18 +139,18 @@ TEST_CASE ("JSON parse arrays", "[json]")
val = std::move(res.get()->first);
REQUIRE(val.is_array());
REQUIRE(val.array().size() == 1);
REQUIRE(val.array()[0].is_number());
REQUIRE(val.array()[0].number() == 123);
REQUIRE(val.array()[0].is_integer());
REQUIRE(val.array()[0].integer() == 123);
res = Json::parse("[123, 456]");
REQUIRE(res);
val = std::move(res.get()->first);
REQUIRE(val.is_array());
REQUIRE(val.array().size() == 2);
REQUIRE(val.array()[0].is_number());
REQUIRE(val.array()[0].number() == 123);
REQUIRE(val.array()[1].is_number());
REQUIRE(val.array()[1].number() == 456);
REQUIRE(val.array()[0].is_integer());
REQUIRE(val.array()[0].integer() == 123);
REQUIRE(val.array()[1].is_integer());
REQUIRE(val.array()[1].integer() == 456);
res = Json::parse("[123, 456, [null]]");
REQUIRE(res);
@ -155,5 +178,8 @@ TEST_CASE ("JSON parse full file", "[json]")
;
auto res = Json::parse(json);
if (!res) {
std::cerr << res.error()->format() << '\n';
}
REQUIRE(res);
}

View File

@ -333,6 +333,11 @@ int main(const int argc, const char* const* const argv)
auto flags = Strings::split(*v, ',');
if (std::find(flags.begin(), flags.end(), "binarycaching") != flags.end()) GlobalState::g_binary_caching = true;
}
const auto vcpkg_disable_metrics_env = System::get_environment_variable("VCPKG_DISABLE_METRICS");
if (vcpkg_disable_metrics_env.has_value())
{
Metrics::g_metrics.lock()->set_disabled(true);
}
const VcpkgCmdArguments args = VcpkgCmdArguments::create_from_command_line(argc, argv);
@ -340,8 +345,20 @@ int main(const int argc, const char* const* const argv)
if (const auto p = args.printmetrics.get()) Metrics::g_metrics.lock()->set_print_metrics(*p);
if (const auto p = args.sendmetrics.get()) Metrics::g_metrics.lock()->set_send_metrics(*p);
if (const auto p = args.disable_metrics.get()) Metrics::g_metrics.lock()->set_disabled(*p);
if (const auto p = args.debug.get()) Debug::g_debugging = *p;
if (args.sendmetrics.has_value() && !Metrics::g_metrics.lock()->metrics_enabled())
{
System::print2(System::Color::warning,
"Warning: passed either --sendmetrics or --no-sendmetrics, but metrics are disabled.\n");
}
if (args.printmetrics.has_value() && !Metrics::g_metrics.lock()->metrics_enabled())
{
System::print2(System::Color::warning,
"Warning: passed either --printmetrics or --no-printmetrics, but metrics are disabled.\n");
}
if (Debug::g_debugging)
{
inner(args);

View File

@ -5,6 +5,8 @@
#include <vcpkg/base/system.debug.h>
#include <vcpkg/base/unicode.h>
#include <inttypes.h>
namespace vcpkg::Json
{
using VK = ValueKind;
@ -23,7 +25,8 @@ namespace vcpkg::Json
{
std::nullptr_t null;
bool boolean;
int64_t number;
int64_t integer;
double number;
std::string string;
Array array;
Object object;
@ -31,7 +34,8 @@ namespace vcpkg::Json
ValueImpl(ValueKindConstant<VK::Null> vk, std::nullptr_t) : tag(vk), null() { }
ValueImpl(ValueKindConstant<VK::Boolean> vk, bool b) : tag(vk), boolean(b) { }
ValueImpl(ValueKindConstant<VK::Number> vk, int64_t i) : tag(vk), number(i) { }
ValueImpl(ValueKindConstant<VK::Integer> vk, int64_t i) : tag(vk), integer(i) { }
ValueImpl(ValueKindConstant<VK::Number> vk, double d) : tag(vk), number(d) { }
ValueImpl(ValueKindConstant<VK::String> vk, std::string&& s) : tag(vk), string(std::move(s)) { }
ValueImpl(ValueKindConstant<VK::Array> vk, Array&& arr) : tag(vk), array(std::move(arr)) { }
ValueImpl(ValueKindConstant<VK::Object> vk, Object&& obj) : tag(vk), object(std::move(obj)) { }
@ -42,6 +46,7 @@ namespace vcpkg::Json
{
case VK::Null: return internal_assign(VK::Null, &ValueImpl::null, other);
case VK::Boolean: return internal_assign(VK::Boolean, &ValueImpl::boolean, other);
case VK::Integer: return internal_assign(VK::Integer, &ValueImpl::integer, other);
case VK::Number: return internal_assign(VK::Number, &ValueImpl::number, other);
case VK::String: return internal_assign(VK::String, &ValueImpl::string, other);
case VK::Array: return internal_assign(VK::Array, &ValueImpl::array, other);
@ -101,7 +106,12 @@ namespace vcpkg::Json
bool Value::is_null() const noexcept { return kind() == VK::Null; }
bool Value::is_boolean() const noexcept { return kind() == VK::Boolean; }
bool Value::is_number() const noexcept { return kind() == VK::Number; }
bool Value::is_integer() const noexcept { return kind() == VK::Integer; }
bool Value::is_number() const noexcept
{
auto k = kind();
return k == VK::Integer || k == VK::Number;
}
bool Value::is_string() const noexcept { return kind() == VK::String; }
bool Value::is_array() const noexcept { return kind() == VK::Array; }
bool Value::is_object() const noexcept { return kind() == VK::Object; }
@ -111,10 +121,22 @@ namespace vcpkg::Json
vcpkg::Checks::check_exit(VCPKG_LINE_INFO, is_boolean());
return underlying_->boolean;
}
int64_t Value::number() const noexcept
int64_t Value::integer() const noexcept
{
vcpkg::Checks::check_exit(VCPKG_LINE_INFO, is_number());
return underlying_->number;
vcpkg::Checks::check_exit(VCPKG_LINE_INFO, is_integer());
return underlying_->integer;
}
double Value::number() const noexcept
{
auto k = kind();
if (k == VK::Number)
{
return underlying_->number;
}
else
{
return static_cast<double>(integer());
}
}
StringView Value::string() const noexcept
{
@ -155,6 +177,7 @@ namespace vcpkg::Json
{
case ValueKind::Null: return Value::null(nullptr);
case ValueKind::Boolean: return Value::boolean(boolean());
case ValueKind::Integer: return Value::integer(integer());
case ValueKind::Number: return Value::number(number());
case ValueKind::String: return Value::string(string());
case ValueKind::Array: return Value::array(array().clone());
@ -170,10 +193,17 @@ namespace vcpkg::Json
val.underlying_ = std::make_unique<ValueImpl>(ValueKindConstant<VK::Boolean>(), b);
return val;
}
Value Value::number(int64_t i) noexcept
Value Value::integer(int64_t i) noexcept
{
Value val;
val.underlying_ = std::make_unique<ValueImpl>(ValueKindConstant<VK::Number>(), i);
val.underlying_ = std::make_unique<ValueImpl>(ValueKindConstant<VK::Integer>(), i);
return val;
}
Value Value::number(double d) noexcept
{
vcpkg::Checks::check_exit(VCPKG_LINE_INFO, isfinite(d));
Value val;
val.underlying_ = std::make_unique<ValueImpl>(ValueKindConstant<VK::Number>(), d);
return val;
}
Value Value::string(StringView sv) noexcept
@ -211,25 +241,66 @@ namespace vcpkg::Json
}
return arr;
}
Value& Array::push_back(Value&& value)
{
underlying_.push_back(std::move(value));
return underlying_.back();
}
Object& Array::push_back(Object&& obj) { return push_back(Value::object(std::move(obj))).object(); }
Array& Array::push_back(Array&& arr) { return push_back(Value::array(std::move(arr))).array(); }
Value& Array::insert_before(iterator it, Value&& value)
{
size_t index = it - underlying_.begin();
underlying_.insert(it, std::move(value));
return underlying_[index];
}
Object& Array::insert_before(iterator it, Object&& obj)
{
return insert_before(it, Value::object(std::move(obj))).object();
}
Array& Array::insert_before(iterator it, Array&& arr)
{
return insert_before(it, Value::array(std::move(arr))).array();
}
// } struct Array
// struct Object {
void Object::insert(std::string key, Value value) noexcept
Value& Object::insert(std::string key, Value&& value)
{
vcpkg::Checks::check_exit(VCPKG_LINE_INFO, !contains(key));
underlying_.push_back(std::make_pair(std::move(key), std::move(value)));
underlying_.push_back({std::move(key), std::move(value)});
return underlying_.back().second;
}
void Object::insert_or_replace(std::string key, Value value) noexcept
Array& Object::insert(std::string key, Array&& value)
{
return insert(std::move(key), Value::array(std::move(value))).array();
}
Object& Object::insert(std::string key, Object&& value)
{
return insert(std::move(key), Value::object(std::move(value))).object();
}
Value& Object::insert_or_replace(std::string key, Value&& value)
{
auto v = get(key);
if (v)
{
*v = std::move(value);
return *v;
}
else
{
underlying_.push_back(std::make_pair(std::move(key), std::move(value)));
underlying_.push_back({std::move(key), std::move(value)});
return underlying_.back().second;
}
}
Array& Object::insert_or_replace(std::string key, Array&& value)
{
return insert_or_replace(std::move(key), Value::array(std::move(value))).array();
}
Object& Object::insert_or_replace(std::string key, Object&& value)
{
return insert_or_replace(std::move(key), Value::object(std::move(value))).object();
}
auto Object::internal_find_key(StringView key) const noexcept -> underlying_t::const_iterator
{
@ -463,11 +534,15 @@ namespace vcpkg::Json
Value parse_number() noexcept
{
Checks::check_exit(VCPKG_LINE_INFO, is_number_start(cur()));
bool negative = false;
bool floating = false;
bool negative = false; // negative & 0 -> floating, so keep track of it
std::string number_to_parse;
char32_t current = cur();
if (cur() == '-')
{
number_to_parse.push_back('-');
negative = true;
current = next();
if (current == Unicode::end_of_file)
@ -480,54 +555,81 @@ namespace vcpkg::Json
if (current == '0')
{
current = next();
if (current != Unicode::end_of_file)
if (current == '.')
{
if (is_digit(current))
{
add_error("Unexpected digits after a leading zero");
}
if (current == '.')
{
add_error("Found a `.` -- this JSON implementation does not support floating point");
}
number_to_parse.append("0.");
floating = true;
current = next();
}
return Value::number(0);
}
// parse as negative so that someone can write INT64_MIN; otherwise, they'd only be able to get
// -INT64_MAX = INT64_MIN + 1
constexpr auto min_value = std::numeric_limits<int64_t>::min();
int64_t result = 0;
while (current != Unicode::end_of_file && is_digit(current))
{
const int digit = current - '0';
// result * 10 - digit < min_value : remember that result < 0
if (result < (min_value + digit) / 10)
else if (is_digit(current))
{
add_error("Number is too big for an int64_t");
add_error("Unexpected digits after a leading zero");
return Value();
}
result *= 10;
result -= digit;
else
{
if (negative)
{
return Value::number(-0.0);
}
else
{
return Value::integer(0);
}
}
}
while (is_digit(current))
{
number_to_parse.push_back(static_cast<char>(current));
current = next();
}
if (current == '.')
if (!floating && current == '.')
{
add_error("Found a `.` -- this JSON implementation doesn't support floating point");
return Value();
}
if (!negative)
{
if (result == min_value)
floating = true;
number_to_parse.push_back('.');
current = next();
if (!is_digit(current))
{
add_error("Number is too big for a uint64_t");
add_error("Expected digits after the decimal point");
return Value();
}
result = -result;
while (is_digit(current))
{
number_to_parse.push_back(static_cast<char>(current));
current = next();
}
}
return Value::number(result);
#ifdef _MSC_VER
#define SCANF sscanf_s
#else
#define SCANF sscanf
#endif
// TODO: switch to `from_chars` once we are able to remove support for old compilers
if (floating)
{
double res;
if (SCANF(number_to_parse.c_str(), "%lf", &res) != 1)
{
add_error(Strings::format("Invalid floating point constant: %s", number_to_parse));
return Value();
}
return Value::number(res);
}
else
{
int64_t res;
if (SCANF(number_to_parse.c_str(), "%" SCNd64, &res) != 1)
{
add_error(Strings::format("Invalid integer constant: %s", number_to_parse));
return Value();
}
return Value::integer(res);
}
#undef SCANF
}
Value parse_keyword() noexcept
@ -630,7 +732,7 @@ namespace vcpkg::Json
auto current = cur();
auto res = std::make_pair(std::string(""), Value());
std::pair<std::string, Value> res = {std::string(""), Value()};
if (current == Unicode::end_of_file)
{
@ -804,118 +906,120 @@ namespace vcpkg::Json
}
// } auto parse()
// auto stringify() {
static std::string& append_unicode_escape(std::string& s, char16_t code_unit)
namespace
{
s.append("\\u");
// AFAIK, there's no standard way of doing this?
constexpr const char hex_digit[16] = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
s.push_back(hex_digit[(code_unit >> 12) & 0x0F]);
s.push_back(hex_digit[(code_unit >> 8) & 0x0F]);
s.push_back(hex_digit[(code_unit >> 4) & 0x0F]);
s.push_back(hex_digit[(code_unit >> 0) & 0x0F]);
return s;
}
// taken from the ECMAScript 2020 standard, 24.5.2.2: Runtime Semantics: QuoteJSONString
static std::string& append_quoted_json_string(std::string& product, StringView sv)
{
// Table 66: JSON Single Character Escape Sequences
constexpr static std::array<std::pair<char32_t, const char*>, 7> escape_sequences = {
std::make_pair(0x0008, R"(\b)"), // BACKSPACE
std::make_pair(0x0009, R"(\t)"), // CHARACTER TABULATION
std::make_pair(0x000A, R"(\n)"), // LINE FEED (LF)
std::make_pair(0x000C, R"(\f)"), // FORM FEED (FF)
std::make_pair(0x000D, R"(\r)"), // CARRIAGE RETURN (CR)
std::make_pair(0x0022, R"(\")"), // QUOTATION MARK
std::make_pair(0x005C, R"(\\)") // REVERSE SOLIDUS
};
// 1. Let product be the String value consisting solely of the code unit 0x0022 (QUOTATION MARK).
product.push_back('"');
// 2. For each code point C in ! UTF16DecodeString(value), do
// (note that we use utf8 instead of utf16)
for (auto code_point : Unicode::Utf8Decoder(sv.begin(), sv.end()))
struct Stringifier
{
bool matched = false; // early exit boolean
// a. If C is listed in the "Code Point" column of Table 66, then
for (auto pr : escape_sequences)
JsonStyle style;
std::string& buffer;
void append_indent(int indent)
{
// i. Set product to the string-concatenation of product and the escape sequence for C as specified in
// the "Escape Sequence" column of the corresponding row.
if (code_point == pr.first)
if (style.use_tabs())
{
product.append(pr.second);
matched = true;
break;
buffer.append(indent, '\t');
}
}
if (matched) break;
else
{
buffer.append(indent * style.spaces(), ' ');
}
};
// b. Else if C has a numeric value less than 0x0020 (SPACE), or if C has the same numeric value as a
// leading surrogate or trailing surrogate, then
if (code_point < 0x0020 || Unicode::utf16_is_surrogate_code_point(code_point))
void append_unicode_escape(char16_t code_unit)
{
// i. Let unit be the code unit whose numeric value is that of C.
// ii. Set product to the string-concatenation of product and UnicodeEscape(unit).
append_unicode_escape(product, static_cast<char16_t>(code_point));
break;
buffer.append("\\u");
// AFAIK, there's no standard way of doing this?
constexpr const char hex_digit[16] = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
buffer.push_back(hex_digit[(code_unit >> 12) & 0x0F]);
buffer.push_back(hex_digit[(code_unit >> 8) & 0x0F]);
buffer.push_back(hex_digit[(code_unit >> 4) & 0x0F]);
buffer.push_back(hex_digit[(code_unit >> 0) & 0x0F]);
}
// c. Else,
// i. Set product to the string-concatenation of product and the UTF16Encoding of C.
// (again, we use utf-8 here instead)
Unicode::utf8_append_code_point(product, code_point);
}
// taken from the ECMAScript 2020 standard, 24.5.2.2: Runtime Semantics: QuoteJSONString
void append_quoted_json_string(StringView sv)
{
// Table 66: JSON Single Character Escape Sequences
constexpr static std::array<std::pair<char32_t, const char*>, 7> escape_sequences = {{
{0x0008, R"(\b)"}, // BACKSPACE
{0x0009, R"(\t)"}, // CHARACTER TABULATION
{0x000A, R"(\n)"}, // LINE FEED (LF)
{0x000C, R"(\f)"}, // FORM FEED (FF)
{0x000D, R"(\r)"}, // CARRIAGE RETURN (CR)
{0x0022, R"(\")"}, // QUOTATION MARK
{0x005C, R"(\\)"} // REVERSE SOLIDUS
}};
// 1. Let product be the String value consisting solely of the code unit 0x0022 (QUOTATION MARK).
buffer.push_back('"');
// 3. Set product to the string-concatenation of product and the code unit 0x0022 (QUOTATION MARK).
product.push_back('"');
// 2. For each code point C in ! UTF16DecodeString(value), do
// (note that we use utf8 instead of utf16)
for (auto code_point : Unicode::Utf8Decoder(sv.begin(), sv.end()))
{
// a. If C is listed in the "Code Point" column of Table 66, then
const auto match = std::find_if(begin(escape_sequences), end(escape_sequences), [code_point](const std::pair<char32_t, const char*>& attempt) {
return attempt.first == code_point;
});
// i. Set product to the string-concatenation of product and the escape sequence for C as
// specified in the "Escape Sequence" column of the corresponding row.
if (match != end(escape_sequences)) {
buffer.append(match->second);
continue;
}
// 4. Return product.
return product;
}
// b. Else if C has a numeric value less than 0x0020 (SPACE), or if C has the same numeric value as
// a leading surrogate or trailing surrogate, then
if (code_point < 0x0020 || Unicode::utf16_is_surrogate_code_point(code_point))
{
// i. Let unit be the code unit whose numeric value is that of C.
// ii. Set product to the string-concatenation of product and UnicodeEscape(unit).
append_unicode_escape(static_cast<char16_t>(code_point));
break;
}
static std::string quote_json_string(StringView sv)
{
std::string product;
append_quoted_json_string(product, sv);
return product;
}
// c. Else,
// i. Set product to the string-concatenation of product and the UTF16Encoding of C.
// (again, we use utf-8 here instead)
Unicode::utf8_append_code_point(buffer, code_point);
}
static void internal_stringify(const Value& value, JsonStyle style, std::string& buffer, int current_indent)
{
const auto append_indent = [&](int indent) {
if (style.use_tabs())
{
buffer.append(indent, '\t');
// 3. Set product to the string-concatenation of product and the code unit 0x0022 (QUOTATION MARK).
buffer.push_back('"');
}
else
void stringify_object(const Object& obj, int current_indent)
{
buffer.append(indent * style.spaces(), ' ');
buffer.push_back('{');
if (obj.size() != 0)
{
bool first = true;
for (const auto& el : obj)
{
if (!first)
{
buffer.push_back(',');
}
first = false;
buffer.append(style.newline());
append_indent(current_indent + 1);
append_quoted_json_string(el.first);
buffer.append(": ");
stringify(el.second, current_indent + 1);
}
buffer.append(style.newline());
append_indent(current_indent);
}
buffer.push_back('}');
}
};
switch (value.kind())
{
case VK::Null: buffer.append("null"); break;
case VK::Boolean:
void stringify_array(const Array& arr, int current_indent)
{
auto v = value.boolean();
buffer.append(v ? "true" : "false");
break;
}
case VK::Number: buffer.append(std::to_string(value.number())); break;
case VK::String:
{
append_quoted_json_string(buffer, value.string());
break;
}
case VK::Array:
{
const auto& arr = value.array();
buffer.push_back('[');
if (arr.size() == 0)
{
@ -936,51 +1040,64 @@ namespace vcpkg::Json
buffer.append(style.newline());
append_indent(current_indent + 1);
internal_stringify(el, style, buffer, current_indent + 1);
stringify(el, current_indent + 1);
}
buffer.append(style.newline());
append_indent(current_indent);
buffer.push_back(']');
}
break;
}
case VK::Object:
void stringify(const Value& value, int current_indent)
{
const auto& obj = value.object();
buffer.push_back('{');
if (obj.size() != 0)
switch (value.kind())
{
bool first = true;
for (const auto& el : obj)
case VK::Null: buffer.append("null"); break;
case VK::Boolean:
{
if (!first)
{
buffer.push_back(',');
}
first = false;
buffer.append(style.newline());
append_indent(current_indent + 1);
auto key = quote_json_string(el.first);
buffer.append(key.begin(), key.end());
buffer.append(": ");
internal_stringify(el.second, style, buffer, current_indent + 1);
auto v = value.boolean();
buffer.append(v ? "true" : "false");
break;
}
// TODO: switch to `to_chars` once we are able to remove support for old compilers
case VK::Integer: buffer.append(std::to_string(value.integer())); break;
case VK::Number: buffer.append(std::to_string(value.number())); break;
case VK::String:
{
append_quoted_json_string(value.string());
break;
}
case VK::Array:
{
stringify_array(value.array(), current_indent);
break;
}
case VK::Object:
{
stringify_object(value.object(), current_indent);
break;
}
buffer.append(style.newline());
append_indent(current_indent);
}
buffer.push_back('}');
break;
}
}
};
}
std::string stringify(const Value& value, JsonStyle style) noexcept
std::string stringify(const Value& value, JsonStyle style)
{
std::string res;
internal_stringify(value, style, res, 0);
Stringifier{style, res}.stringify(value, 0);
return res;
}
std::string stringify(const Object& obj, JsonStyle style)
{
std::string res;
Stringifier{style, res}.stringify_object(obj, 0);
return res;
}
std::string stringify(const Array& arr, JsonStyle style)
{
std::string res;
Stringifier{style, res}.stringify_array(arr, 0);
return res;
}
// } auto stringify()

View File

@ -237,6 +237,7 @@ namespace vcpkg
L"USERDOMAIN_ROAMINGPROFILE",
L"USERNAME",
L"USERPROFILE",
L"VCPKG_DISABLE_METRICS",
L"windir",
// Enables proxy information to be passed to Curl, the underlying download library in cmake.exe
L"http_proxy",
@ -558,6 +559,7 @@ VCPKG_MSVC_WARNING(suppress : 6335) // Leaking process information handle 'proce
(void)env;
Debug::print("system(", cmd_line, ")\n");
fflush(nullptr);
int exit_code = system(cmd_line.c_str());
Debug::print(
"system() returned ", exit_code, " after ", static_cast<unsigned int>(timer.microseconds()), " us\n");
@ -617,6 +619,7 @@ VCPKG_MSVC_WARNING(suppress : 6335) // Leaking process information handle 'proce
Debug::print("popen(", actual_cmd_line, ")\n");
// Flush stdout before launching external process
fflush(stdout);
const auto pipe = popen(actual_cmd_line.c_str(), "r");
if (pipe == nullptr)
{

View File

@ -32,7 +32,7 @@ namespace vcpkg::Commands::Version
#ifndef NDEBUG
+ std::string("-debug")
#endif
+ std::string(Metrics::get_compiled_metrics_enabled() ? "" : "-external");
;
return S_VERSION;
}

View File

@ -6,6 +6,7 @@
#include <vcpkg/base/chrono.h>
#include <vcpkg/base/files.h>
#include <vcpkg/base/hash.h>
#include <vcpkg/base/json.h>
#include <vcpkg/base/strings.h>
#include <vcpkg/base/system.process.h>
@ -29,51 +30,73 @@ namespace vcpkg::Metrics
return "";
}
static std::string generate_random_UUID()
// note: this ignores the bits of these numbers that would be where format and variant go
static std::string uuid_of_integers(uint64_t top, uint64_t bottom)
{
int part_sizes[] = {8, 4, 4, 4, 12};
char uuid[37];
memset(uuid, 0, sizeof(uuid));
int num;
srand(static_cast<int>(time(nullptr)));
int index = 0;
for (int part = 0; part < 5; part++)
// uuid_field_size in bytes, not hex characters
constexpr size_t uuid_top_field_size[] = {4, 2, 2};
constexpr size_t uuid_bottom_field_size[] = {2, 6};
// uuid_field_size in hex characters, not bytes
constexpr size_t uuid_size = 8 + 1 + 4 + 1 + 4 + 1 + 4 + 1 + 12;
constexpr static char hex[17] = "0123456789abcdef";
constexpr static auto write_byte = [](std::string& res, std::uint8_t bits) {
res.push_back(hex[(bits >> 4) & 0x0F]);
res.push_back(hex[(bits >> 0) & 0x0F]);
};
// set the version bits to 4
top &= 0xFFFF'FFFF'FFFF'0FFFULL;
top |= 0x0000'0000'0000'4000ULL;
// set the variant bits to 2 (variant one)
bottom &= 0x3FFF'FFFF'FFFF'FFFFULL;
bottom |= 0x8000'0000'0000'0000ULL;
std::string res;
res.reserve(uuid_size);
bool first = true;
size_t start_byte = 0;
for (auto field_size : uuid_top_field_size)
{
if (part > 0)
if (!first)
{
uuid[index] = '-';
index++;
res.push_back('-');
}
// Generating UUID format version 4
// http://en.wikipedia.org/wiki/Universally_unique_identifier
for (int i = 0; i < part_sizes[part]; i++, index++)
first = false;
for (size_t i = start_byte; i < start_byte + field_size; ++i)
{
if (part == 2 && i == 0)
{
num = 4;
}
else if (part == 4 && i == 0)
{
num = (rand() % 4) + 8;
}
else
{
num = rand() % 16;
}
if (num < 10)
{
uuid[index] = static_cast<char>('0' + num);
}
else
{
uuid[index] = static_cast<char>('a' + (num - 10));
}
auto shift = 64 - (i + 1) * 8;
write_byte(res, (top >> shift) & 0xFF);
}
start_byte += field_size;
}
return uuid;
start_byte = 0;
for (auto field_size : uuid_bottom_field_size)
{
res.push_back('-');
for (size_t i = start_byte; i < start_byte + field_size; ++i)
{
auto shift = 64 - (i + 1) * 8;
write_byte(res, (bottom >> shift) & 0xFF);
}
start_byte += field_size;
}
return res;
}
// UUID format version 4, variant 1
// http://en.wikipedia.org/wiki/Universally_unique_identifier
// [0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}
static std::string generate_random_UUID()
{
std::random_device rnd{};
std::uniform_int_distribution<std::uint64_t> uid{};
return uuid_of_integers(uid(rnd), uid(rnd));
}
static const std::string& get_session_id()
@ -82,37 +105,6 @@ namespace vcpkg::Metrics
return ID;
}
static std::string to_json_string(const std::string& str)
{
std::string encoded = "\"";
for (auto&& ch : str)
{
if (ch == '\\')
{
encoded.append("\\\\");
}
else if (ch == '"')
{
encoded.append("\\\"");
}
else if (ch < 0x20 || static_cast<unsigned char>(ch) >= 0x80)
{
// Note: this treats incoming Strings as Latin-1
static constexpr const char HEX[16] = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
encoded.append("\\u00");
encoded.push_back(HEX[ch / 16]);
encoded.push_back(HEX[ch % 16]);
}
else
{
encoded.push_back(ch);
}
}
encoded.push_back('"');
return encoded;
}
static std::string get_os_version_string()
{
#if defined(_WIN32)
@ -150,91 +142,89 @@ namespace vcpkg::Metrics
std::string user_id = generate_random_UUID();
std::string user_timestamp;
std::string timestamp = get_current_date_time();
std::string properties;
std::string measurements;
std::vector<std::string> buildtime_names;
std::vector<std::string> buildtime_times;
Json::Object properties;
Json::Object measurements;
Json::Array buildtime_names;
Json::Array buildtime_times;
void track_property(const std::string& name, const std::string& value)
{
if (properties.size() != 0) properties.push_back(',');
properties.append(to_json_string(name));
properties.push_back(':');
properties.append(to_json_string(value));
properties.insert_or_replace(name, Json::Value::string(value));
}
void track_metric(const std::string& name, double value)
{
if (measurements.size() != 0) measurements.push_back(',');
measurements.append(to_json_string(name));
measurements.push_back(':');
measurements.append(std::to_string(value));
measurements.insert_or_replace(name, Json::Value::number(value));
}
void track_buildtime(const std::string& name, double value)
{
buildtime_names.push_back(name);
buildtime_times.push_back(std::to_string(value));
buildtime_names.push_back(Json::Value::string(name));
buildtime_times.push_back(Json::Value::number(value));
}
std::string format_event_data_template() const
{
auto props_plus_buildtimes = properties;
auto props_plus_buildtimes = properties.clone();
if (buildtime_names.size() > 0)
{
if (props_plus_buildtimes.size() > 0) props_plus_buildtimes.push_back(',');
props_plus_buildtimes.append(Strings::format(R"("buildnames_1": [%s], "buildtimes": [%s])",
Strings::join(",", buildtime_names, to_json_string),
Strings::join(",", buildtime_times)));
props_plus_buildtimes.insert("buildnames_1", Json::Value::array(buildtime_names.clone()));
props_plus_buildtimes.insert("buildtimes", Json::Value::array(buildtime_times.clone()));
}
const std::string& session_id = get_session_id();
return Strings::format(R"([{
"ver": 1,
"name": "Microsoft.ApplicationInsights.Event",
"time": "%s",
"sampleRate": 100.000000,
"seq": "0:0",
"iKey": "b4e88960-4393-4dd9-ab8e-97e8fe6d7603",
"flags": 0.000000,
"tags": {
"ai.device.os": "Other",
"ai.device.osVersion": "%s-%s",
"ai.session.id": "%s",
"ai.user.id": "%s",
"ai.user.accountAcquisitionDate": "%s"
},
"data": {
"baseType": "EventData",
"baseData": {
"ver": 2,
"name": "commandline_test7",
"properties": { %s },
"measurements": { %s }
}
}
}])",
timestamp,
Json::Array arr = Json::Array();
Json::Object& obj = arr.push_back(Json::Object());
obj.insert("ver", Json::Value::integer(1));
obj.insert("name", Json::Value::string("Microsoft.ApplicationInsights.Event"));
obj.insert("time", Json::Value::string(timestamp));
obj.insert("sampleRate", Json::Value::number(100.0));
obj.insert("seq", Json::Value::string("0:0"));
obj.insert("iKey", Json::Value::string("b4e88960-4393-4dd9-ab8e-97e8fe6d7603"));
obj.insert("flags", Json::Value::integer(0));
{
Json::Object& tags = obj.insert("tags", Json::Object());
tags.insert("ai.device.os", Json::Value::string("Other"));
const char* os_name =
#if defined(_WIN32)
"Windows",
"Windows";
#elif defined(__APPLE__)
"OSX",
"OSX";
#elif defined(__linux__)
"Linux",
"Linux";
#elif defined(__FreeBSD__)
"FreeBSD",
"FreeBSD";
#elif defined(__unix__)
"Unix",
"Unix";
#else
"Other",
"Other";
#endif
get_os_version_string(),
session_id,
user_id,
user_timestamp,
props_plus_buildtimes,
measurements);
tags.insert("ai.device.osVersion",
Json::Value::string(Strings::format("%s-%s", os_name, get_os_version_string())));
tags.insert("ai.session.id", Json::Value::string(get_session_id()));
tags.insert("ai.user.id", Json::Value::string(user_id));
tags.insert("ai.user.accountAcquisitionDate", Json::Value::string(user_timestamp));
}
{
Json::Object& data = obj.insert("data", Json::Object());
data.insert("baseType", Json::Value::string("EventData"));
Json::Object& base_data = data.insert("baseData", Json::Object());
base_data.insert("ver", Json::Value::integer(2));
base_data.insert("name", Json::Value::string("commandline_test7"));
base_data.insert("properties", Json::Value::object(std::move(props_plus_buildtimes)));
base_data.insert("measurements", Json::Value::object(measurements.clone()));
}
return Json::stringify(arr, vcpkg::Json::JsonStyle());
}
};
@ -247,12 +237,39 @@ namespace vcpkg::Metrics
#endif
;
static bool g_should_print_metrics = false;
static bool g_metrics_disabled =
#if VCPKG_DISABLE_METRICS
true
#else
false
#endif
;
bool get_compiled_metrics_enabled() { return !VCPKG_DISABLE_METRICS; }
// for child vcpkg processes, we also want to disable metrics
static void set_vcpkg_disable_metrics_environment_variable(bool disabled)
{
#if defined(_WIN32)
SetEnvironmentVariableW(L"VCPKG_DISABLE_METRICS", disabled ? L"1" : nullptr);
#else
if (disabled)
{
setenv("VCPKG_DISABLE_METRICS", "1", true);
}
else
{
unsetenv("VCPKG_DISABLE_METRICS");
}
#endif
}
std::string get_MAC_user()
{
#if defined(_WIN32)
if (!g_metrics.lock()->metrics_enabled())
{
return "{}";
}
auto getmac = System::cmd_execute_and_capture_output("getmac");
if (getmac.exit_code != 0) return "0";
@ -293,20 +310,55 @@ namespace vcpkg::Metrics
void Metrics::set_print_metrics(bool should_print_metrics) { g_should_print_metrics = should_print_metrics; }
void Metrics::track_metric(const std::string& name, double value) { g_metricmessage.track_metric(name, value); }
void Metrics::set_disabled(bool disabled)
{
set_vcpkg_disable_metrics_environment_variable(disabled);
g_metrics_disabled = disabled;
}
bool Metrics::metrics_enabled()
{
#if VCPKG_DISABLE_METRICS
return false;
#else
return !g_metrics_disabled;
#endif
}
void Metrics::track_metric(const std::string& name, double value)
{
if (!metrics_enabled())
{
return;
}
g_metricmessage.track_metric(name, value);
}
void Metrics::track_buildtime(const std::string& name, double value)
{
if (!metrics_enabled())
{
return;
}
g_metricmessage.track_buildtime(name, value);
}
void Metrics::track_property(const std::string& name, const std::string& value)
{
if (!metrics_enabled())
{
return;
}
g_metricmessage.track_property(name, value);
}
void Metrics::upload(const std::string& payload)
{
if (!metrics_enabled())
{
return;
}
#if !defined(_WIN32)
Util::unused(payload);
#else
@ -402,6 +454,11 @@ namespace vcpkg::Metrics
void Metrics::flush()
{
if (!metrics_enabled())
{
return;
}
const std::string payload = g_metricmessage.format_event_data_template();
if (g_should_print_metrics) std::cerr << payload << "\n";
if (!g_should_send_metrics) return;

View File

@ -212,6 +212,11 @@ namespace vcpkg
parse_switch(true, "printmetrics", args.printmetrics);
continue;
}
if (arg == "--disable-metrics")
{
parse_switch(true, "printmetrics", args.disable_metrics);
continue;
}
if (arg == "--no-sendmetrics")
{
parse_switch(false, "sendmetrics", args.sendmetrics);
@ -222,6 +227,11 @@ namespace vcpkg
parse_switch(false, "printmetrics", args.printmetrics);
continue;
}
if (arg == "--no-disable-metrics")
{
parse_switch(false, "printmetrics", args.disable_metrics);
continue;
}
if (arg == "--featurepackages")
{
parse_switch(true, "featurepackages", args.featurepackages);