telemetry.h 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. // SPDX-FileCopyrightText: 2017 Citra Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #pragma once
  4. #include <chrono>
  5. #include <map>
  6. #include <memory>
  7. #include <string>
  8. #include "common/common_funcs.h"
  9. #include "common/common_types.h"
  10. namespace Common::Telemetry {
  11. /// Field type, used for grouping fields together in the final submitted telemetry log
  12. enum class FieldType : u8 {
  13. None = 0, ///< No specified field group
  14. App, ///< yuzu application fields (e.g. version, branch, etc.)
  15. Session, ///< Emulated session fields (e.g. title ID, log, etc.)
  16. Performance, ///< Emulated performance (e.g. fps, emulated CPU speed, etc.)
  17. UserFeedback, ///< User submitted feedback (e.g. star rating, user notes, etc.)
  18. UserConfig, ///< User configuration fields (e.g. emulated CPU core, renderer, etc.)
  19. UserSystem, ///< User system information (e.g. host CPU type, RAM, etc.)
  20. };
  21. struct VisitorInterface;
  22. /**
  23. * Interface class for telemetry data fields.
  24. */
  25. class FieldInterface {
  26. public:
  27. virtual ~FieldInterface() = default;
  28. /**
  29. * Accept method for the visitor pattern.
  30. * @param visitor Reference to the visitor that will visit this field.
  31. */
  32. virtual void Accept(VisitorInterface& visitor) const = 0;
  33. /**
  34. * Gets the name of this field.
  35. * @returns Name of this field as a string.
  36. */
  37. virtual const std::string& GetName() const = 0;
  38. };
  39. /**
  40. * Represents a telemetry data field, i.e. a unit of data that gets logged and submitted to our
  41. * telemetry web service.
  42. */
  43. template <typename T>
  44. class Field : public FieldInterface {
  45. public:
  46. YUZU_NON_COPYABLE(Field);
  47. Field(FieldType type_, std::string_view name_, T value_)
  48. : name(name_), type(type_), value(std::move(value_)) {}
  49. ~Field() override = default;
  50. Field(Field&&) noexcept = default;
  51. Field& operator=(Field&& other) noexcept = default;
  52. void Accept(VisitorInterface& visitor) const override;
  53. [[nodiscard]] const std::string& GetName() const override {
  54. return name;
  55. }
  56. /**
  57. * Returns the type of the field.
  58. */
  59. [[nodiscard]] FieldType GetType() const {
  60. return type;
  61. }
  62. /**
  63. * Returns the value of the field.
  64. */
  65. [[nodiscard]] const T& GetValue() const {
  66. return value;
  67. }
  68. [[nodiscard]] bool operator==(const Field& other) const {
  69. return (type == other.type) && (name == other.name) && (value == other.value);
  70. }
  71. [[nodiscard]] bool operator!=(const Field& other) const {
  72. return !operator==(other);
  73. }
  74. private:
  75. std::string name; ///< Field name, must be unique
  76. FieldType type{}; ///< Field type, used for grouping fields together
  77. T value; ///< Field value
  78. };
  79. /**
  80. * Collection of data fields that have been logged.
  81. */
  82. class FieldCollection final {
  83. public:
  84. YUZU_NON_COPYABLE(FieldCollection);
  85. FieldCollection() = default;
  86. ~FieldCollection() = default;
  87. FieldCollection(FieldCollection&&) noexcept = default;
  88. FieldCollection& operator=(FieldCollection&&) noexcept = default;
  89. /**
  90. * Accept method for the visitor pattern, visits each field in the collection.
  91. * @param visitor Reference to the visitor that will visit each field.
  92. */
  93. void Accept(VisitorInterface& visitor) const;
  94. /**
  95. * Creates a new field and adds it to the field collection.
  96. * @param type Type of the field to add.
  97. * @param name Name of the field to add.
  98. * @param value Value for the field to add.
  99. */
  100. template <typename T>
  101. void AddField(FieldType type, std::string_view name, T value) {
  102. return AddField(std::make_unique<Field<T>>(type, name, std::move(value)));
  103. }
  104. /**
  105. * Adds a new field to the field collection.
  106. * @param field Field to add to the field collection.
  107. */
  108. void AddField(std::unique_ptr<FieldInterface> field);
  109. private:
  110. std::map<std::string, std::unique_ptr<FieldInterface>> fields;
  111. };
  112. /**
  113. * Telemetry fields visitor interface class. A backend to log to a web service should implement
  114. * this interface.
  115. */
  116. struct VisitorInterface {
  117. virtual ~VisitorInterface() = default;
  118. virtual void Visit(const Field<bool>& field) = 0;
  119. virtual void Visit(const Field<double>& field) = 0;
  120. virtual void Visit(const Field<float>& field) = 0;
  121. virtual void Visit(const Field<u8>& field) = 0;
  122. virtual void Visit(const Field<u16>& field) = 0;
  123. virtual void Visit(const Field<u32>& field) = 0;
  124. virtual void Visit(const Field<u64>& field) = 0;
  125. virtual void Visit(const Field<s8>& field) = 0;
  126. virtual void Visit(const Field<s16>& field) = 0;
  127. virtual void Visit(const Field<s32>& field) = 0;
  128. virtual void Visit(const Field<s64>& field) = 0;
  129. virtual void Visit(const Field<std::string>& field) = 0;
  130. virtual void Visit(const Field<const char*>& field) = 0;
  131. virtual void Visit(const Field<std::chrono::microseconds>& field) = 0;
  132. /// Completion method, called once all fields have been visited
  133. virtual void Complete() = 0;
  134. virtual bool SubmitTestcase() = 0;
  135. };
  136. /**
  137. * Empty implementation of VisitorInterface that drops all fields. Used when a functional
  138. * backend implementation is not available.
  139. */
  140. struct NullVisitor final : public VisitorInterface {
  141. YUZU_NON_COPYABLE(NullVisitor);
  142. NullVisitor() = default;
  143. ~NullVisitor() override = default;
  144. void Visit(const Field<bool>& /*field*/) override {}
  145. void Visit(const Field<double>& /*field*/) override {}
  146. void Visit(const Field<float>& /*field*/) override {}
  147. void Visit(const Field<u8>& /*field*/) override {}
  148. void Visit(const Field<u16>& /*field*/) override {}
  149. void Visit(const Field<u32>& /*field*/) override {}
  150. void Visit(const Field<u64>& /*field*/) override {}
  151. void Visit(const Field<s8>& /*field*/) override {}
  152. void Visit(const Field<s16>& /*field*/) override {}
  153. void Visit(const Field<s32>& /*field*/) override {}
  154. void Visit(const Field<s64>& /*field*/) override {}
  155. void Visit(const Field<std::string>& /*field*/) override {}
  156. void Visit(const Field<const char*>& /*field*/) override {}
  157. void Visit(const Field<std::chrono::microseconds>& /*field*/) override {}
  158. void Complete() override {}
  159. bool SubmitTestcase() override {
  160. return false;
  161. }
  162. };
  163. /// Appends build-specific information to the given FieldCollection,
  164. /// such as branch name, revision hash, etc.
  165. void AppendBuildInfo(FieldCollection& fc);
  166. /// Appends CPU-specific information to the given FieldCollection,
  167. /// such as instruction set extensions, etc.
  168. void AppendCPUInfo(FieldCollection& fc);
  169. /// Appends OS-specific information to the given FieldCollection,
  170. /// such as platform name, etc.
  171. void AppendOSInfo(FieldCollection& fc);
  172. } // namespace Common::Telemetry