/* * Copyright (c) 2022 Project CHIP Authors * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ #include "Log.h" #include "ToCertificateString.h" #include #include namespace chip { namespace trace { namespace logging { namespace { constexpr uint8_t kSpacePerIndent = 4; uint8_t gIndentLevel = 0; void ENFORCE_FORMAT(1, 2) LogFormatted(const char * format, ...) { char buffer[CHIP_CONFIG_LOG_MESSAGE_MAX_SIZE + 1] = {}; int indentation = gIndentLevel * kSpacePerIndent; snprintf(buffer, sizeof(buffer), "%*s", indentation, ""); va_list args; va_start(args, format); vsnprintf(&buffer[indentation], sizeof(buffer) - static_cast(indentation), format, args); va_end(args); ChipLogDetail(DataManagement, "%s", buffer); } const char * ToHexString(chip::ByteSpan source, MutableCharSpan destination) { memset(destination.data(), '\0', destination.size()); if (source.size() == 0) { return destination.data(); } CHIP_ERROR err = Encoding::BytesToHex(source.data(), source.size(), destination.data(), destination.size(), Encoding::HexFlags::kUppercase); if (CHIP_NO_ERROR != err) { LogErrorOnFailure(err); return destination.data(); } return destination.data(); } } // namespace void Log(const char * name, ByteSpan & data) { if (data.empty()) { return; } // If the size of the data is larger than half of the maximum size for a log message (minus 1 for null-termination), // reduce the size of the data to fit within this limit. // The limit is half the size of the message because we will be logging a hex representation of that data, at 2 chars per byte. if (data.size() > (CHIP_CONFIG_LOG_MESSAGE_MAX_SIZE / 2) - 1) { data.reduce_size((CHIP_CONFIG_LOG_MESSAGE_MAX_SIZE / 2) - 1); } char buffer[CHIP_CONFIG_LOG_MESSAGE_MAX_SIZE] = { 0 }; chip::MutableCharSpan destination(buffer); // Check if the size of the data can be cast to uint16_t. // If yes, log the name and size of the data followed by its hexadecimal string representation. // If no, log the name and a marker indicating the size exceeds UINT16_MAX, followed by the data's hexadecimal string. CanCastTo(data.size()) ? LogFormatted("%s (%u) = %s", name, static_cast(data.size()), ToHexString(data, destination)) : LogFormatted("%s (>UINT16_MAX) = %s", name, ToHexString(data, destination)); } void Log(const char * name, CharSpan & data) { if (data.empty()) { return; } CanCastTo(data.size()) ? LogFormatted("%s (%u) = %.*s", name, static_cast(data.size()), static_cast(data.size()), data.data()) : LogFormatted("%s (>UINT16_MAX) = %.*s", name, static_cast(data.size()), data.data()); } void Log(const char * name, uint16_t value) { LogFormatted("%s = %u", name, value); } void Log(const char * name, uint32_t value) { LogFormatted("%s = %u", name, value); } void Log(const char * name, const char * value) { LogFormatted("%s = %s", name, value); } void Log(const char * name) { LogFormatted("%s", name); } void LogAsHex(const char * name, uint8_t value) { LogFormatted("%s = 0x%02x", name, value); } void LogAsHex(const char * name, uint16_t value) { LogFormatted("%s = 0x%04x", name, value); } void LogAsHex(const char * name, uint64_t value) { LogFormatted("%s = " ChipLogFormatX64, name, ChipLogValueX64(value)); } void LogCertificate(const char * name, const ByteSpan & data) { char buffer[CHIP_CONFIG_LOG_MESSAGE_MAX_SIZE] = {}; chip::MutableCharSpan destination(buffer); CanCastTo(data.size()) ? LogFormatted("%s (%u) =", name, static_cast(data.size())) : LogFormatted("%s (>UINT16_MAX) =", name); LogFormatted("{\n%s", ToCertificateString(data, destination)); LogFormatted("}"); LogFormatted(" "); } void LogCertificateRequest(const char * name, const ByteSpan & data) { char buffer[CHIP_CONFIG_LOG_MESSAGE_MAX_SIZE] = {}; chip::MutableCharSpan destination(buffer); CanCastTo(data.size()) ? LogFormatted("%s (%u) =", name, static_cast(data.size())) : LogFormatted("%s (>UINT16_MAX) =", name); LogFormatted("{\n%s", ToCertificateRequestString(data, destination)); LogFormatted("}"); LogFormatted(" "); } void IncreaseLogIndent() { LogFormatted("{"); gIndentLevel++; } void DecreaseLogIndent() { gIndentLevel--; LogFormatted("}"); if (gIndentLevel == 0) { LogFormatted(" "); } } ScopedLogIndent::ScopedLogIndent(const char * name) { LogFormatted("%s =", name); IncreaseLogIndent(); } ScopedLogIndent::~ScopedLogIndent() { DecreaseLogIndent(); } ScopedLogIndentWithFlags::ScopedLogIndentWithFlags(const char * name, uint8_t flags) { LogFormatted("%s (0x%02x) =", name, flags); IncreaseLogIndent(); } ScopedLogIndentWithFlags::~ScopedLogIndentWithFlags() { DecreaseLogIndent(); } ScopedLogIndentWithSize::ScopedLogIndentWithSize(const char * name, size_t size) { CanCastTo(size) ? LogFormatted("%s (%u bytes) =", name, static_cast(size)) : LogFormatted("%s (>UINT16_MAX) =", name); IncreaseLogIndent(); } ScopedLogIndentWithSize::~ScopedLogIndentWithSize() { DecreaseLogIndent(); } } // namespace logging } // namespace trace } // namespace chip