blob: 854da17d224b12afe0edd96eaee3fb0dfa7a89eb [file] [log] [blame]
Brian Silvermanf665d692013-02-17 22:11:39 -08001#include "aos/atom_code/logging/atom_logging.h"
2
3#include <stdarg.h>
4#include <stdio.h>
5#include <string.h>
6#include <time.h>
7#include <sys/types.h>
8#include <errno.h>
9#include <unistd.h>
10#include <limits.h>
11#include <sys/prctl.h>
12
13#include <algorithm>
14
15#include "aos/common/die.h"
16#include "aos/common/logging/logging_impl.h"
17#include "aos/atom_code/thread_local.h"
18#include "aos/atom_code/ipc_lib/queue.h"
19
20namespace aos {
21namespace logging {
22namespace {
23
24using internal::Context;
25
26AOS_THREAD_LOCAL Context *my_context(NULL);
27
Brian Silvermanab6615c2013-03-05 20:29:29 -080028::std::string GetMyName() {
Brian Silvermanf665d692013-02-17 22:11:39 -080029 // The maximum number of characters that can make up a thread name.
30 // The docs are unclear if it can be 16 characters with no '\0', so we'll be
31 // safe by adding our own where necessary.
32 static const size_t kThreadNameLength = 16;
33
Brian Silvermanab6615c2013-03-05 20:29:29 -080034 ::std::string process_name(program_invocation_short_name);
Brian Silvermanf665d692013-02-17 22:11:39 -080035
36 char thread_name_array[kThreadNameLength + 1];
37 if (prctl(PR_GET_NAME, thread_name_array) != 0) {
38 Die("prctl(PR_GET_NAME, %p) failed with %d: %s\n",
39 thread_name_array, errno, strerror(errno));
40 }
41 thread_name_array[sizeof(thread_name_array) - 1] = '\0';
Brian Silvermanab6615c2013-03-05 20:29:29 -080042 ::std::string thread_name(thread_name_array);
Brian Silvermanf665d692013-02-17 22:11:39 -080043
44 // If the first bunch of characters are the same.
45 // We cut off comparing at the shorter of the 2 strings because one or the
46 // other often ends up cut off.
47 if (strncmp(thread_name.c_str(), process_name.c_str(),
Brian Silvermanab6615c2013-03-05 20:29:29 -080048 ::std::min(thread_name.length(), process_name.length())) == 0) {
Brian Silvermanf665d692013-02-17 22:11:39 -080049 // This thread doesn't have an actual name.
50 return process_name;
51 }
52
53 return process_name + '.' + thread_name;
54}
55
Brian Silverman08661c72013-09-01 17:24:38 -070056RawQueue *queue;
Brian Silvermanf665d692013-02-17 22:11:39 -080057
58} // namespace
59namespace internal {
60
61Context *Context::Get() {
62 if (my_context == NULL) {
63 my_context = new Context();
Brian Silvermanab6615c2013-03-05 20:29:29 -080064 my_context->name = GetMyName();
65 if (my_context->name.size() + 1 > sizeof(LogMessage::name)) {
66 Die("logging: process/thread name '%s' is too long\n",
67 my_context->name.c_str());
68 }
Brian Silvermanf665d692013-02-17 22:11:39 -080069 my_context->source = getpid();
70 }
71 return my_context;
72}
73
74void Context::Delete() {
75 delete my_context;
76 my_context = NULL;
77}
78
79} // namespace internal
80namespace atom {
81namespace {
82
Brian Silvermanab6615c2013-03-05 20:29:29 -080083class AtomQueueLogImplementation : public LogImplementation {
Brian Silvermanf665d692013-02-17 22:11:39 -080084 virtual void DoLog(log_level level, const char *format, va_list ap) {
Brian Silvermana6d1b562013-09-01 14:39:39 -070085 LogMessage *message = static_cast<LogMessage *>(queue->GetMessage());
Brian Silvermanf665d692013-02-17 22:11:39 -080086 if (message == NULL) {
87 LOG(FATAL, "queue get message failed\n");
88 }
89
90 internal::FillInMessage(level, format, ap, message);
91
92 Write(message);
93 }
94};
95
96} // namespace
97
98void Register() {
99 Init();
100
Brian Silverman08661c72013-09-01 17:24:38 -0700101 queue = RawQueue::Fetch("LoggingQueue", sizeof(LogMessage), 1323, 1500);
Brian Silvermanf665d692013-02-17 22:11:39 -0800102 if (queue == NULL) {
103 Die("logging: couldn't fetch queue\n");
104 }
105
Brian Silvermanab6615c2013-03-05 20:29:29 -0800106 AddImplementation(new AtomQueueLogImplementation());
Brian Silvermanf665d692013-02-17 22:11:39 -0800107}
108
109const LogMessage *ReadNext(int flags, int *index) {
Brian Silvermana6d1b562013-09-01 14:39:39 -0700110 return static_cast<const LogMessage *>(queue->ReadMessageIndex(flags, index));
Brian Silvermanf665d692013-02-17 22:11:39 -0800111}
112
113const LogMessage *ReadNext() {
Brian Silverman08661c72013-09-01 17:24:38 -0700114 return ReadNext(RawQueue::kBlock);
Brian Silvermanf665d692013-02-17 22:11:39 -0800115}
116
117const LogMessage *ReadNext(int flags) {
118 const LogMessage *r = NULL;
119 do {
Brian Silvermana6d1b562013-09-01 14:39:39 -0700120 r = static_cast<const LogMessage *>(queue->ReadMessage(flags));
Brian Silvermanf665d692013-02-17 22:11:39 -0800121 // not blocking means return a NULL if that's what it gets
Brian Silverman08661c72013-09-01 17:24:38 -0700122 } while ((flags & RawQueue::kBlock) && r == NULL);
Brian Silvermanf665d692013-02-17 22:11:39 -0800123 return r;
124}
125
126LogMessage *Get() {
Brian Silvermana6d1b562013-09-01 14:39:39 -0700127 return static_cast<LogMessage *>(queue->GetMessage());
Brian Silvermanf665d692013-02-17 22:11:39 -0800128}
129
130void Free(const LogMessage *msg) {
Brian Silvermana6d1b562013-09-01 14:39:39 -0700131 queue->FreeMessage(msg);
Brian Silvermanf665d692013-02-17 22:11:39 -0800132}
133
134void Write(LogMessage *msg) {
Brian Silverman08661c72013-09-01 17:24:38 -0700135 if (!queue->WriteMessage(msg, RawQueue::kOverride)) {
Brian Silvermanf665d692013-02-17 22:11:39 -0800136 LOG(FATAL, "writing failed");
137 }
138}
139
140} // namespace atom
141} // namespace logging
142} // namespace aos