blob: b0645bb3980d77769577b45a24c0637ca6e141c7 [file] [log] [blame]
/*
* 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 <lib/support/BytesToHex.h>
#include <lib/support/SafeInt.h>
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<size_t>(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<uint16_t>(data.size())
? LogFormatted("%s (%u) = %s", name, static_cast<uint16_t>(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<uint16_t>(data.size())
? LogFormatted("%s (%u) = %.*s", name, static_cast<uint16_t>(data.size()), static_cast<int>(data.size()), data.data())
: LogFormatted("%s (>UINT16_MAX) = %.*s", name, static_cast<int>(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<uint16_t>(data.size()) ? LogFormatted("%s (%u) =", name, static_cast<uint16_t>(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<uint16_t>(data.size()) ? LogFormatted("%s (%u) =", name, static_cast<uint16_t>(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<uint16_t>(size) ? LogFormatted("%s (%u bytes) =", name, static_cast<uint16_t>(size))
: LogFormatted("%s (>UINT16_MAX) =", name);
IncreaseLogIndent();
}
ScopedLogIndentWithSize::~ScopedLogIndentWithSize()
{
DecreaseLogIndent();
}
} // namespace logging
} // namespace trace
} // namespace chip