Files
UnrealEngine/Engine/Source/Developer/TraceInsights/Private/Insights/ViewModels/LogMessage.cpp
2025-05-18 13:04:45 +08:00

173 lines
5.1 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "LogMessage.h"
#include "Misc/OutputDeviceHelper.h"
#include "Misc/ScopeLock.h"
// TraceServices
#include "TraceServices/Model/Log.h"
// TraceInsightsCore
#include "InsightsCore/Common/TimeUtils.h"
// TraceInsights
#include "Insights/Log.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// FLogMessageRecord
////////////////////////////////////////////////////////////////////////////////////////////////////
FLogMessageRecord::FLogMessageRecord(const TraceServices::FLogMessageInfo& TraceLogMessage)
: Time(TraceLogMessage.Time)
//, Category(FText::FromString(TraceLogMessage.Category))
//, Message(FText::FromString(TraceLogMessage.Message))
, File(FText::FromString(TraceLogMessage.File))
, Line(TraceLogMessage.Line)
, Index(static_cast<uint32>(TraceLogMessage.Index))
, Verbosity(TraceLogMessage.Verbosity)
{
// Strip the "Log" prefix.
FString CategoryStr(TraceLogMessage.Category->Name);
if (CategoryStr.StartsWith(TEXT("Log")))
{
CategoryStr.RightChopInline(3, EAllowShrinking::No);
}
Category = FText::FromString(MoveTemp(CategoryStr));
// Strip the trailing whitespaces (ex. some messages ends with "\n" and we do not want the LogView rows to have an unnecessary increased height).
FString MessageStr(TraceLogMessage.Message);
MessageStr.TrimEndInline();
Message = FText::FromString(MoveTemp(MessageStr));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
FText FLogMessageRecord::GetIndexAsText() const
{
return FText::AsNumber(Index);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
FText FLogMessageRecord::GetTimeAsText() const
{
return FText::FromString(UE::Insights::FormatTimeHMS(Time, UE::Insights::FTimeValue::Microsecond));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
FText FLogMessageRecord::GetVerbosityAsText() const
{
return FText::FromString(FString(ToString(Verbosity)));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
FText FLogMessageRecord::GetLineAsText() const
{
return FText::AsNumber(Line);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
FText FLogMessageRecord::ToDisplayString() const
{
FTextBuilder TextBuilder;
TextBuilder.AppendLine(GetTimeAsText());
TextBuilder.AppendLineFormat(NSLOCTEXT("SLogView", "CategoryLine", "Category: {0}"), Category);
TextBuilder.AppendLineFormat(NSLOCTEXT("SLogView", "MessageLine", "Message: {0}"), Message);
return TextBuilder.ToText();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// FLogMessageCache
////////////////////////////////////////////////////////////////////////////////////////////////////
FLogMessageCache::FLogMessageCache()
{
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void FLogMessageCache::SetSession(TSharedPtr<const TraceServices::IAnalysisSession> InSession)
{
if (Session != InSession)
{
Reset();
Session = InSession;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void FLogMessageCache::Reset()
{
FScopeLock Lock(&CriticalSection);
Map.Reset();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
FLogMessageRecord& FLogMessageCache::Get(uint64 Index)
{
{
FScopeLock Lock(&CriticalSection);
if (Map.Contains(Index))
{
return Map[Index];
}
// Just an arbitrary limit. Will purge the cache after this limit, to avoid using too much memory.
if (Map.Num() > 10000)
{
Map.Reset();
}
}
if (Session.IsValid())
{
TraceServices::FAnalysisSessionReadScope SessionReadScope(*Session.Get());
const TraceServices::ILogProvider& LogProvider = TraceServices::ReadLogProvider(*Session.Get());
LogProvider.ReadMessage(Index, [this, Index](const TraceServices::FLogMessageInfo& Message)
{
LLM_SCOPE_BYTAG(Insights);
FScopeLock Lock(&CriticalSection);
FLogMessageRecord Entry(Message);
Map.Add(Index, MoveTemp(Entry));
});
}
{
FScopeLock Lock(&CriticalSection);
if (Map.Contains(Index))
{
return Map[Index];
}
}
return InvalidEntry;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
TSharedPtr<FLogMessageRecord> FLogMessageCache::GetUncached(uint64 Index) const
{
TSharedPtr<FLogMessageRecord> EntryPtr;
if (Session.IsValid())
{
TraceServices::FAnalysisSessionReadScope SessionReadScope(*Session.Get());
const TraceServices::ILogProvider& LogProvider = TraceServices::ReadLogProvider(*Session.Get());
LogProvider.ReadMessage(Index, [&EntryPtr](const TraceServices::FLogMessageInfo& Message)
{
EntryPtr = MakeShared<FLogMessageRecord>(Message);
});
}
return EntryPtr;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////