Agrarsense
LogFile.cpp
Go to the documentation of this file.
1// Copyright (c) 2024 FrostBit Software Lab at the Lapland University of Applied Sciences
2//
3// This work is licensed under the terms of the MIT license.
4// For a copy, see <https://opensource.org/licenses/MIT>.
5
6#include "LogFile.h"
9
10#include "Misc/Paths.h"
11
12#include <filesystem>
13#include <iostream>
14#include <iomanip>
15#include <ctime>
16
17ULogFile* ULogFile::CreateLogFile(const FString& FileNameWithoutExtension, FLogFileSettings Settings)
18{
19 ULogFile* LogFile = NewObject<ULogFile>(ULogFile::StaticClass());
20 LogFile->AddToRoot();
21 if (LogFile)
22 {
23 LogFile->Create(FileNameWithoutExtension, Settings);
24 }
25
26 return LogFile;
27}
28
30{
31
32}
33
35{
37 Close();
38}
39
40void ULogFile::Create(const FString& FileNameWithoutExtension, FLogFileSettings Settings)
41{
42 CurrentSettings = Settings;
43
44 FString ProjectPath = UAgrarsensePaths::GetDataFolder();
45 FString Folder = FString("/Logs/");
46 FString LogDirPath = FPaths::Combine(*ProjectPath, *Folder);
47
48 if (!std::filesystem::exists(TCHAR_TO_UTF8(*LogDirPath)))
49 {
50 if (!std::filesystem::create_directory(TCHAR_TO_UTF8(*LogDirPath)))
51 {
52 // Failed to create the directory, return
53 return;
54 }
55 }
56
57 FString LogFilePath;
58
59 if (Settings.OverrideFilePath && !Settings.FilePath.IsEmpty())
60 {
61 LogFilePath = FPaths::Combine(*Settings.FilePath, *FileNameWithoutExtension) + TEXT(".txt");
62 }
63 else
64 {
65 LogFilePath = FPaths::Combine(*LogDirPath, *FileNameWithoutExtension) + TEXT(".txt");
66 }
67
68 FilePath = LogFilePath;
69
71 {
73 // Clear file if it exists
74 Clear();
75 break;
76
78 // Append to existing file if it exists
79 break;
80
82 {
83 // Create unique file by adding number to the end until we find unique filename
84 int suffix = 0;
85 FString UniqueFileName = FileNameWithoutExtension + TEXT("_") + FString::FromInt(suffix++);
86 FString UniqueLogFilePath = FPaths::Combine(*LogDirPath, *UniqueFileName) + TEXT(".txt");
87
88 while (std::filesystem::exists(TCHAR_TO_UTF8(*UniqueLogFilePath)))
89 {
90 UniqueFileName = FileNameWithoutExtension + TEXT("_") + FString::FromInt(suffix++) + TEXT(".txt");
91 UniqueLogFilePath = FPaths::Combine(*LogDirPath, *UniqueFileName);
92 }
93
94 LogFilePath = UniqueLogFilePath;
95 break;
96 }
97
98 default:
99 break;
100 }
101
102 // Try to create the .txt file
103 std::ofstream newFile(TCHAR_TO_UTF8(*LogFilePath), std::ios::app);
104 if (newFile.is_open())
105 {
106 newFile.close();
107 }
108 else
109 {
110 std::ifstream file(TCHAR_TO_UTF8(*LogFilePath));
111 if (file.good())
112 {
113 // The file already exists, return
114 file.close();
115 }
116 }
117}
118
119void ULogFile::Write(const FString& Text)
120{
121 if (FilePath.IsEmpty() || !IsValid(this))
122 {
123 return;
124 }
125
127 {
129 {
131 }
132 else
133 {
134 // Add message to queue (with timestamp if CurrentSettings.Timestamp) and return
135 FString MessageToAdd = Text;
137 {
138 std::time_t now = std::time(nullptr);
139 std::tm tm_time = *std::localtime(&now);
140 char timestamp[12];
141 std::strftime(timestamp, sizeof(timestamp), "[%H:%M:%S] ", &tm_time);
142 MessageToAdd = FString(timestamp) + Text;
143 }
144 MessageQueue.Add(MessageToAdd);
145 }
146
147 return;
148 }
149
150 WriteToFile(Text, true);
151}
152
154{
155 if (LogFileStream.is_open())
156 {
157 LogFileStream.close();
158 }
159}
160
162{
163 if (std::filesystem::exists(TCHAR_TO_UTF8(*FilePath)))
164 {
165 std::ofstream clearFile(TCHAR_TO_UTF8(*FilePath), std::ofstream::out | std::ofstream::trunc);
166 clearFile.close();
167 }
168}
169
171{
172 if (IsValid(this))
173 {
175 Close();
176 ConditionalBeginDestroy();
177 }
178}
179
181{
183}
184
186{
187 if (MessageQueue.IsEmpty() || FilePath.IsEmpty())
188 {
189 return;
190 }
191
192 if (!LogFileStream.is_open())
193 {
194 std::string filePathString(TCHAR_TO_UTF8(*FilePath));
195 LogFileStream.open(filePathString, std::ios::app);
196 if (!LogFileStream.is_open())
197 {
198 // Failed to open the file, return
199 return;
200 }
201 }
202
203 for (const FString& Message : MessageQueue)
204 {
205 WriteToFile(Message, false);
206 }
207
208 MessageQueue.Empty();
209
211 {
212 LogFileStream.close();
213 }
214}
215
216void ULogFile::WriteToFile(const FString& Text, bool UseTimestamp)
217{
218 if (FilePath.IsEmpty() || !IsValid(this))
219 {
220 return;
221 }
222
223 if (!LogFileStream.is_open())
224 {
225 std::string filePathString(TCHAR_TO_UTF8(*FilePath));
226 LogFileStream.open(filePathString, std::ios::app);
227 if (!LogFileStream.is_open())
228 {
229 // Failed to open the file, return
230 return;
231 }
232 }
233
234 if (UseTimestamp && CurrentSettings.Timestamp)
235 {
236 std::time_t now = std::time(nullptr);
237 std::tm tm_time = *std::localtime(&now);
238 char timestamp[12];
239 std::strftime(timestamp, sizeof(timestamp), "[%H:%M:%S] ", &tm_time);
240
241 LogFileStream << timestamp << TCHAR_TO_UTF8(*Text) << std::endl;
242 }
243 else
244 {
245 LogFileStream << TCHAR_TO_UTF8(*Text) << std::endl;
246 }
247
249 {
250 LogFileStream.close();
251 }
252}
static FString GetDataFolder()
static void OpenFileExplorer(FString Path)
ULogFile()
Definition: LogFile.cpp:29
void Clear()
Definition: LogFile.cpp:161
void Destroy()
Definition: LogFile.cpp:170
void WriteQueuedMessages()
Definition: LogFile.cpp:185
FLogFileSettings CurrentSettings
Definition: LogFile.h:145
void OpenFilePath()
Definition: LogFile.cpp:180
void Write(const FString &Text)
Definition: LogFile.cpp:119
std::ofstream LogFileStream
Definition: LogFile.h:149
void Close()
Definition: LogFile.cpp:153
void WriteToFile(const FString &Text, bool UseTimestamp)
Definition: LogFile.cpp:216
static ULogFile * CreateLogFile(const FString &FileNameWithoutExtension, FLogFileSettings Settings=FLogFileSettings())
Definition: LogFile.cpp:17
void Create(const FString &FileNameWithoutExtension, FLogFileSettings Settings)
Definition: LogFile.cpp:40
FString FilePath
Definition: LogFile.h:147
~ULogFile()
Definition: LogFile.cpp:34
TArray< FString > MessageQueue
Definition: LogFile.h:143
bool KeepFileOpen
Definition: LogFile.h:42
bool Timestamp
Definition: LogFile.h:39
FString FilePath
Definition: LogFile.h:54
FFileWriteOptions FileWriteOptions
Definition: LogFile.h:45
int32 QueueLength
Definition: LogFile.h:48
bool OverrideFilePath
Definition: LogFile.h:51
FFileCreationOptions FileCreationOptions
Definition: LogFile.h:36