blob: e3c12130237144d146ed3c1008e3217ab4bb4a38 [file] [log] [blame]
/*
*
* Copyright (c) 2025 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 <algorithm>
#include <esp_err.h>
#include <esp_log.h>
#include <lib/support/CHIPMemString.h>
#include <tracing/esp32_diagnostic_trace/Counter.h>
#include <tracing/esp32_diagnostic_trace/DiagnosticTracing.h>
namespace chip {
namespace Tracing {
namespace Diagnostics {
namespace {
// Implements a murmurhash with 0 seed.
uint32_t MurmurHash(const void * key)
{
const uint32_t kMultiplier = 0x5bd1e995;
const uint32_t kShift = 24;
const unsigned char * data = (const unsigned char *) key;
uint32_t hash = 0;
while (*data)
{
uint32_t value = *data++;
value *= kMultiplier;
value ^= value >> kShift;
value *= kMultiplier;
hash *= kMultiplier;
hash ^= value;
}
hash ^= hash >> 13;
hash *= kMultiplier;
hash ^= hash >> 15;
if (hash == 0)
{
ChipLogError(DeviceLayer, "MurmurHash resulted in a hash value of 0");
}
return hash;
}
} // anonymous namespace
constexpr size_t kPermitListMaxSize = CONFIG_MAX_PERMIT_LIST_SIZE;
using HashValue = uint32_t;
/*
* gPermitList will allow the following traces to be stored in the storage instance while other traces are skipped.
* Only traces with scope in gPermitList are allowed.
* Used for MATTER_TRACE_SCOPE()
*/
HashValue gPermitList[kPermitListMaxSize] = { MurmurHash("PASESession"),
MurmurHash("CASESession"),
MurmurHash("NetworkCommissioning"),
MurmurHash("GeneralCommissioning"),
MurmurHash("OperationalCredentials"),
MurmurHash("CASEServer"),
MurmurHash("Fabric") };
/*
* gSkipList will skip the following traces from being stored in the storage instance while other traces are stored.
* Used for MATTER_TRACE_INSTANT()
*/
HashValue gSkipList[kPermitListMaxSize] = {
MurmurHash("Resolver"),
};
bool IsPresent(const char * str, HashValue * list)
{
for (int i = 0; i < kPermitListMaxSize; i++)
{
if (list[i] == 0)
{
break;
}
if (MurmurHash(str) == list[i])
{
return true;
}
}
return false;
}
void ESP32Diagnostics::LogMessageReceived(MessageReceivedInfo & info) {}
void ESP32Diagnostics::LogMessageSend(MessageSendInfo & info) {}
void ESP32Diagnostics::LogNodeLookup(NodeLookupInfo & info) {}
void ESP32Diagnostics::LogNodeDiscovered(NodeDiscoveredInfo & info) {}
void ESP32Diagnostics::LogNodeDiscoveryFailed(NodeDiscoveryFailedInfo & info) {}
void ESP32Diagnostics::LogMetricEvent(const MetricEvent & event)
{
VerifyOrReturn(mStorageInstance != nullptr, ChipLogError(DeviceLayer, "Diagnostic Storage Instance cannot be NULL"));
DiagnosticEntry entry;
switch (event.ValueType())
{
case ValueType::kInt32:
ChipLogDetail(DeviceLayer, "The value of %s is %" PRId32, event.key(), event.ValueInt32());
Platform::CopyString(entry.label, event.key());
entry.intValue = event.ValueInt32();
entry.type = Diagnostics::ValueType::kSignedInteger;
entry.timestamps_ms_since_boot = esp_log_timestamp();
ReturnOnFailure(mStorageInstance->Store(entry));
break;
case ValueType::kUInt32:
ChipLogDetail(DeviceLayer, "The value of %s is %" PRIu32, event.key(), event.ValueUInt32());
Platform::CopyString(entry.label, event.key());
entry.uintValue = event.ValueUInt32();
entry.type = Diagnostics::ValueType::kUnsignedInteger;
entry.timestamps_ms_since_boot = esp_log_timestamp();
ReturnOnFailure(mStorageInstance->Store(entry));
break;
case ValueType::kChipErrorCode:
ChipLogDetail(DeviceLayer, "The value of %s is error with code %lu ", event.key(), event.ValueErrorCode());
break;
case ValueType::kUndefined:
ChipLogDetail(DeviceLayer, "The value of %s is undefined", event.key());
break;
default:
ChipLogDetail(DeviceLayer, "The value of %s is of an UNKNOWN TYPE", event.key());
break;
}
}
void ESP32Diagnostics::TraceCounter(const char * label)
{
ESPDiagnosticCounter & counter = ESPDiagnosticCounter::GetInstance();
counter.IncreaseCount(label);
ReturnOnFailure(counter.ReportMetrics(label, mStorageInstance));
}
void ESP32Diagnostics::TraceBegin(const char * label, const char * group)
{
VerifyOrReturn(IsPresent(group, gPermitList));
ReturnOnFailure(StoreDiagnostics(label, group));
}
void ESP32Diagnostics::TraceEnd(const char * label, const char * group) {}
void ESP32Diagnostics::TraceInstant(const char * label, const char * value)
{
VerifyOrReturn(!IsPresent(value, gSkipList));
ReturnOnFailure(StoreDiagnostics(label, value));
}
CHIP_ERROR ESP32Diagnostics::StoreDiagnostics(const char * label, const char * group)
{
VerifyOrReturnError(mStorageInstance != nullptr, CHIP_ERROR_INCORRECT_STATE,
ChipLogError(DeviceLayer, "Diagnostic Storage Instance cannot be NULL"));
// Create diagnostic entry
DiagnosticEntry entry;
Platform::CopyString(entry.label, label);
Platform::CopyString(entry.stringValue, group);
entry.type = Diagnostics::ValueType::kCharString;
entry.timestamps_ms_since_boot = esp_log_timestamp();
return mStorageInstance->Store(entry);
}
} // namespace Diagnostics
} // namespace Tracing
} // namespace chip