BitLab 0.1.0
BitLab: A Browser for the Bitcoin P2P Network and Blockchain
Loading...
Searching...
No Matches
log.c File Reference
#include "log.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "utils.h"

Go to the source code of this file.

Functions

const char * create_logs_dir ()
 Create logs directory used to create the logs directory if it does not exist.
 
void init_logging (const char *filename)
 Initialize logging used to initialize the logging system, open and preserve the log file.
 
void log_message (log_level level, const char *filename, const char *source_file, const char *format,...)
 Log a message used to log a message to the console or a file.
 
void finish_logging ()
 Finish logging used to finish logging and close the log file.
 

Variables

static struct loggers logs = { PTHREAD_MUTEX_INITIALIZER, {NULL}, 0 }
 
static const char * logs_dir = NULL
 

Function Documentation

◆ create_logs_dir()

const char * create_logs_dir ( )

Create logs directory used to create the logs directory if it does not exist.

Returns
The logs directory.

Definition at line 20 of file log.c.

21{
22 const char* home = getenv("HOME");
23 if (home == NULL)
24 return NULL;
25 const char* suffix = "/.bitlab/logs";
26 char* logs_dir = malloc(strlen(home) + strlen(suffix) + 1);
27 if (logs_dir == NULL)
28 return NULL;
29 strcpy(logs_dir, home);
30 strcat(logs_dir, suffix);
31 return logs_dir;
32}
static const char * logs_dir
Definition log.c:18

References logs_dir.

Referenced by init_logging(), and log_message().

◆ finish_logging()

void finish_logging ( )

Finish logging used to finish logging and close the log file.

Definition at line 199 of file log.c.

200{
201 while (logs.is_initializing)
202 {
203 usleep(10000); // 10 ms
204 }
205 pthread_mutex_lock(&logs.log_mutex);
206 for (int i = 0; i < MAX_LOG_FILES; ++i)
207 {
208 if (logs.array[i] != NULL)
209 {
210 fclose(logs.array[i]->file);
211 if (logs.array[i]->filename != NULL)
212 free(logs.array[i]->filename);
213 free(logs.array[i]);
214 logs.array[i] = NULL;
215 }
216 }
217 pthread_mutex_unlock(&logs.log_mutex);
218 if (logs_dir != NULL)
219 {
220 free((void*)logs_dir);
221 logs_dir = NULL;
222 }
223}
static struct loggers logs
Definition log.c:16
#define MAX_LOG_FILES
Definition log.h:9
char * filename
Definition log.h:44
FILE * file
Definition log.h:45
logger * array[MAX_LOG_FILES]
Definition log.h:58
int is_initializing
Definition log.h:59
pthread_mutex_t log_mutex
Definition log.h:57
void usleep(unsigned int usec)

References loggers::array, logger::file, logger::filename, loggers::is_initializing, loggers::log_mutex, logs, logs_dir, MAX_LOG_FILES, and usleep().

Referenced by run_bitlab().

◆ init_logging()

void init_logging ( const char *  filename)

Initialize logging used to initialize the logging system, open and preserve the log file.

Parameters
log_fileThe log file to write to.

Definition at line 34 of file log.c.

35{
37 if (logs_dir != NULL)
38 {
39 free((void*)logs_dir);
40 }
42 struct stat st = { 0 };
43
44 if (stat(logs_dir, &st) == -1)
45 {
46 if (mkdir(logs_dir, 0700) != 0)
47 {
48 perror("Failed to create logs directory");
50 free((void*)logs_dir); // Free logs_dir on error
51 logs_dir = NULL;
52 return;
53 }
54 }
55
56 char full_path[BUFFER_SIZE];
57 snprintf(full_path, sizeof(full_path), "%s/%s", logs_dir, filename);
58
59 pthread_mutex_lock(&logs.log_mutex);
60 for (int i = 0; i < MAX_LOG_FILES; ++i)
61 {
62 if (logs.array[i] == NULL)
63 {
64 logs.array[i] = (struct logger*)malloc(sizeof(logger));
65 logs.array[i]->filename = (char*)malloc(strlen(full_path) + 1);
66 if (logs.array[i]->filename == NULL)
67 {
68 perror("Failed to allocate memory for filename");
69 free(logs.array[i]);
70 logs.array[i] = NULL;
71 break;
72 }
73 snprintf(logs.array[i]->filename, strlen(full_path) + 1, "%s", full_path);
74 logs.array[i]->file = fopen(full_path, "a");
75 if (logs.array[i]->file == NULL)
76 {
77 perror("Failed to open log file");
78 free(logs.array[i]->filename);
79 free(logs.array[i]);
80 logs.array[i] = NULL;
81 }
82 break;
83 }
84 }
86 pthread_mutex_unlock(&logs.log_mutex);
87}
const char * create_logs_dir()
Create logs directory used to create the logs directory if it does not exist.
Definition log.c:20
The logger structure used to store the logger for the logging system.
Definition log.h:43
#define BUFFER_SIZE
Definition utils.h:12

References loggers::array, BUFFER_SIZE, create_logs_dir(), logger::file, logger::filename, loggers::is_initializing, loggers::log_mutex, logs, logs_dir, and MAX_LOG_FILES.

Referenced by connect_to_peer(), and run_bitlab().

◆ log_message()

void log_message ( log_level  level,
const char *  filename,
const char *  source_file,
const char *  format,
  ... 
)

Log a message used to log a message to the console or a file.

Parameters
levelThe log level.
log_fileThe file that the log message is destined for.
source_fileThe source file that the log message is from.
formatThe format of the log message.
...The arguments for the format.

Definition at line 89 of file log.c.

90{
91 if (logs_dir == NULL)
92 {
94 if (logs_dir == NULL)
95 {
96 fprintf(stderr, "Failed to create logs directory\n");
97 return;
98 }
99 }
100
101 char full_path[BUFFER_SIZE];
102 snprintf(full_path, sizeof(full_path), "%s/%s", logs_dir, filename);
103
104 pthread_mutex_lock(&logs.log_mutex);
105
106 FILE* log = NULL;
107 for (int i = 0; i < MAX_LOG_FILES; ++i)
108 {
109 if (logs.array[i] != NULL && !strcmp(logs.array[i]->filename, full_path))
110 {
111 log = logs.array[i]->file;
112 break;
113 }
114 }
115
116 if (log == NULL)
117 {
118 // Try to create and open the log file if it doesn't exist
119 log = fopen(full_path, "a");
120 if (log == NULL)
121 {
122 pthread_mutex_unlock(&logs.log_mutex);
123 fprintf(stderr, "Failed to create or open log file: %s\n", full_path);
124 return;
125 }
126
127 // Add the new log file to the logs array
128 for (int i = 0; i < MAX_LOG_FILES; ++i)
129 {
130 if (logs.array[i] == NULL)
131 {
132 logs.array[i] = (struct logger*)malloc(sizeof(logger));
133 logs.array[i]->filename = (char*)malloc(strlen(full_path) + 1);
134 if (logs.array[i]->filename == NULL)
135 {
136 perror("Failed to allocate memory for filename");
137 free(logs.array[i]);
138 logs.array[i] = NULL;
139 fclose(log);
140 pthread_mutex_unlock(&logs.log_mutex);
141 return;
142 }
143 snprintf(logs.array[i]->filename, strlen(full_path) + 1, "%s", full_path);
144 logs.array[i]->file = log;
145 break;
146 }
147 }
148 }
149
150 int timeout = 0;
151 int error = 0;
152
153 error = flock(fileno(log), LOCK_EX | LOCK_NB);
154 while (error == -1 && (errno == EWOULDBLOCK || errno == EAGAIN))
155 {
157 timeout += LOCKED_FILE_RETRY_TIME;
158
159 if (timeout > LOCKED_FILE_TIMEOUT)
160 {
161 fprintf(stderr, "Log file locking timed out: %s\n", full_path);
162 pthread_mutex_unlock(&logs.log_mutex);
163 return;
164 }
165 error = flock(fileno(log), LOCK_EX | LOCK_NB);
166 }
167
168 fseek(log, 0, SEEK_END);
169
170 const char* level_str;
171 switch (level)
172 {
173 case LOG_DEBUG: level_str = "DEBUG"; break;
174 case LOG_INFO: level_str = "INFO"; break;
175 case LOG_WARN: level_str = "WARN"; break;
176 case LOG_ERROR: level_str = "ERROR"; break;
177 case LOG_FATAL: level_str = "FATAL"; break;
178 default: level_str = "UNKNOWN"; break;
179 }
180
181 char timestamp[TIMESTAMP_LENGTH];
183
184 char message[1024];
185 va_list args;
186 va_start(args, format);
187 vsnprintf(message, sizeof(message), format, args);
188 va_end(args);
189
190 fprintf(log, "%s - %s - %s - %s\n", timestamp, level_str, source_file, message);
191
192 fflush(log);
193
194 flock(fileno(log), LOCK_UN);
195
196 pthread_mutex_unlock(&logs.log_mutex);
197}
#define LOCKED_FILE_RETRY_TIME
Definition log.h:15
@ LOG_ERROR
Definition log.h:32
@ LOG_INFO
Definition log.h:30
@ LOG_DEBUG
Definition log.h:29
@ LOG_FATAL
Definition log.h:33
@ LOG_WARN
Definition log.h:31
#define LOCKED_FILE_TIMEOUT
Definition log.h:16
int fileno(FILE *__stream)
void get_formatted_timestamp(char *buffer, size_t buffer_size)
Get the formatted timestamp.
Definition utils.c:25
#define TIMESTAMP_LENGTH
Definition utils.h:11

References loggers::array, BUFFER_SIZE, create_logs_dir(), logger::file, logger::filename, fileno(), get_formatted_timestamp(), LOCKED_FILE_RETRY_TIME, LOCKED_FILE_TIMEOUT, LOG_DEBUG, LOG_ERROR, LOG_FATAL, LOG_INFO, loggers::log_mutex, LOG_WARN, logs, logs_dir, MAX_LOG_FILES, TIMESTAMP_LENGTH, and usleep().

Referenced by add_peer_to_queue(), build_inv_message(), cli_clear(), cli_connect(), cli_disconnect(), cli_echo(), cli_exec_line(), cli_exit(), cli_getaddr(), cli_getblocks(), cli_getdata(), cli_getheaders(), cli_help(), cli_history(), cli_info(), cli_inv(), cli_list(), cli_peer_discovery(), cli_ping(), cli_tx(), cli_whoami(), connect_to_peer(), disconnect(), force_stop_peer_discovery(), handle_cli(), handle_inv_message(), handle_peer_discovery(), init_program_state(), is_in_private_network(), is_valid_domain_address(), lookup_address(), peer_communication(), run_bitlab(), send_addr(), send_getaddr_and_wait(), send_getblocks_and_wait(), send_getdata_and_wait(), send_getheaders_and_wait(), send_headers(), send_inv_and_wait(), send_ping(), send_tx(), send_verack(), set_peer_discovery(), set_peer_discovery_dns_domain(), start_peer_discovery_progress(), thread_runner(), and write_var_int().

Variable Documentation

◆ logs

struct loggers logs = { PTHREAD_MUTEX_INITIALIZER, {NULL}, 0 }
static

Definition at line 16 of file log.c.

16{ PTHREAD_MUTEX_INITIALIZER, {NULL}, 0 };

Referenced by finish_logging(), init_logging(), and log_message().

◆ logs_dir

const char* logs_dir = NULL
static

Definition at line 18 of file log.c.

Referenced by create_history_dir(), create_logs_dir(), finish_logging(), init_logging(), and log_message().