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