DataModelLogger.h 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. /*
  2. * Copyright (c) 2022 Project CHIP Authors
  3. * All rights reserved.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. */
  18. #pragma once
  19. #include <string>
  20. #include <app-common/zap-generated/cluster-objects.h>
  21. #include <app/ConcreteAttributePath.h>
  22. #include <app/ConcreteCommandPath.h>
  23. #include <app/EventHeader.h>
  24. #include <app/MessageDef/StatusIB.h>
  25. #include <app/data-model/DecodableList.h>
  26. #include <commands/common/RemoteDataModelLogger.h>
  27. #include <lib/support/BytesToHex.h>
  28. class DataModelLogger
  29. {
  30. public:
  31. static CHIP_ERROR LogAttribute(const chip::app::ConcreteDataAttributePath & path, chip::TLV::TLVReader * data);
  32. static CHIP_ERROR LogCommand(const chip::app::ConcreteCommandPath & path, chip::TLV::TLVReader * data);
  33. static CHIP_ERROR LogEvent(const chip::app::EventHeader & header, chip::TLV::TLVReader * data);
  34. private:
  35. static CHIP_ERROR LogValue(const char * label, size_t indent, bool value)
  36. {
  37. DataModelLogger::LogString(label, indent, value ? "TRUE" : "FALSE");
  38. return CHIP_NO_ERROR;
  39. }
  40. static CHIP_ERROR LogValue(const char * label, size_t indent, chip::CharSpan value)
  41. {
  42. DataModelLogger::LogString(label, indent, std::string(value.data(), value.size()));
  43. return CHIP_NO_ERROR;
  44. }
  45. static CHIP_ERROR LogValue(const char * label, size_t indent, chip::ByteSpan value)
  46. {
  47. // CHIP_CONFIG_LOG_MESSAGE_MAX_SIZE includes various prefixes we don't
  48. // control (timestamps, process ids, etc). Let's assume (hope?) that
  49. // those prefixes use up no more than half the total available space.
  50. // Right now it looks like the prefixes are 45 chars out of a 255 char
  51. // buffer.
  52. char buffer[CHIP_CONFIG_LOG_MESSAGE_MAX_SIZE / 2];
  53. size_t prefixSize = ComputePrefixSize(label, indent);
  54. if (prefixSize > ArraySize(buffer))
  55. {
  56. DataModelLogger::LogString("", 0, "Prefix is too long to fit in buffer");
  57. return CHIP_ERROR_INTERNAL;
  58. }
  59. const size_t availableSize = ArraySize(buffer) - prefixSize;
  60. // Each byte ends up as two hex characters.
  61. const size_t bytesPerLogCall = availableSize / 2;
  62. std::string labelStr(label);
  63. while (value.size() > bytesPerLogCall)
  64. {
  65. ReturnErrorOnFailure(
  66. chip::Encoding::BytesToUppercaseHexString(value.data(), bytesPerLogCall, &buffer[0], ArraySize(buffer)));
  67. LogString(labelStr, indent, buffer);
  68. value = value.SubSpan(bytesPerLogCall);
  69. // For the second and following lines, make it clear that they are
  70. // continuation lines by replacing the label with "....".
  71. labelStr.replace(labelStr.begin(), labelStr.end(), labelStr.size(), '.');
  72. }
  73. ReturnErrorOnFailure(chip::Encoding::BytesToUppercaseHexString(value.data(), value.size(), &buffer[0], ArraySize(buffer)));
  74. LogString(labelStr, indent, buffer);
  75. return CHIP_NO_ERROR;
  76. }
  77. template <typename X,
  78. typename std::enable_if_t<
  79. std::is_integral<X>::value && !std::is_same<std::remove_cv_t<std::remove_reference_t<X>>, bool>::value, int> = 0>
  80. static CHIP_ERROR LogValue(const char * label, size_t indent, X value)
  81. {
  82. DataModelLogger::LogString(label, indent, std::to_string(value));
  83. return CHIP_NO_ERROR;
  84. }
  85. template <typename X, typename std::enable_if_t<std::is_floating_point<X>::value, int> = 0>
  86. static CHIP_ERROR LogValue(const char * label, size_t indent, X value)
  87. {
  88. DataModelLogger::LogString(label, indent, std::to_string(value));
  89. return CHIP_NO_ERROR;
  90. }
  91. template <typename X, typename std::enable_if_t<std::is_enum<X>::value, int> = 0>
  92. static CHIP_ERROR LogValue(const char * label, size_t indent, X value)
  93. {
  94. return DataModelLogger::LogValue(label, indent, chip::to_underlying(value));
  95. }
  96. template <typename X>
  97. static CHIP_ERROR LogValue(const char * label, size_t indent, chip::BitFlags<X> value)
  98. {
  99. return DataModelLogger::LogValue(label, indent, value.Raw());
  100. }
  101. template <typename T>
  102. static CHIP_ERROR LogValue(const char * label, size_t indent, const chip::app::DataModel::DecodableList<T> & value)
  103. {
  104. size_t count = 0;
  105. ReturnErrorOnFailure(value.ComputeSize(&count));
  106. DataModelLogger::LogString(label, indent, std::to_string(count) + " entries");
  107. auto iter = value.begin();
  108. size_t i = 0;
  109. while (iter.Next())
  110. {
  111. ++i;
  112. std::string itemLabel = std::string("[") + std::to_string(i) + "]";
  113. ReturnErrorOnFailure(DataModelLogger::LogValue(itemLabel.c_str(), indent + 1, iter.GetValue()));
  114. }
  115. if (iter.GetStatus() != CHIP_NO_ERROR)
  116. {
  117. DataModelLogger::LogString(indent + 1, "List truncated due to invalid value");
  118. }
  119. return iter.GetStatus();
  120. }
  121. template <typename T>
  122. static CHIP_ERROR LogValue(const char * label, size_t indent, const chip::app::DataModel::Nullable<T> & value)
  123. {
  124. if (value.IsNull())
  125. {
  126. DataModelLogger::LogString(label, indent, "null");
  127. return CHIP_NO_ERROR;
  128. }
  129. return DataModelLogger::LogValue(label, indent, value.Value());
  130. }
  131. template <typename T>
  132. static CHIP_ERROR LogValue(const char * label, size_t indent, const chip::Optional<T> & value)
  133. {
  134. if (value.HasValue())
  135. {
  136. return DataModelLogger::LogValue(label, indent, value.Value());
  137. }
  138. return CHIP_NO_ERROR;
  139. }
  140. #include <zap-generated/cluster/logging/DataModelLogger.h>
  141. static void LogString(size_t indent, const std::string string) { LogString("", indent, string); }
  142. static void LogString(const std::string label, size_t indent, const std::string string)
  143. {
  144. std::string prefix = ComputePrefix(label, indent);
  145. ChipLogProgress(chipTool, "%s%s", prefix.c_str(), string.c_str());
  146. }
  147. private:
  148. static std::string ComputePrefix(const std::string label, size_t indent)
  149. {
  150. std::string prefix;
  151. for (size_t i = 0; i < indent; ++i)
  152. {
  153. prefix.append(" ");
  154. }
  155. if (label.size() > 0)
  156. {
  157. prefix.append(label);
  158. prefix.append(":");
  159. }
  160. prefix.append(" ");
  161. return prefix;
  162. }
  163. static size_t ComputePrefixSize(const std::string label, size_t indent) { return ComputePrefix(label, indent).size(); }
  164. };