blob: 6ea3b2491df2af416a06d23861cdbf784110ab6c [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
Brian Silvermana6d1b562013-09-01 14:39:39 -070020using ::aos::Queue;
21
Brian Silvermanf665d692013-02-17 22:11:39 -080022namespace aos {
23namespace logging {
24namespace {
25
26using internal::Context;
27
28AOS_THREAD_LOCAL Context *my_context(NULL);
29
Brian Silvermanab6615c2013-03-05 20:29:29 -080030::std::string GetMyName() {
Brian Silvermanf665d692013-02-17 22:11:39 -080031 // The maximum number of characters that can make up a thread name.
32 // The docs are unclear if it can be 16 characters with no '\0', so we'll be
33 // safe by adding our own where necessary.
34 static const size_t kThreadNameLength = 16;
35
Brian Silvermanab6615c2013-03-05 20:29:29 -080036 ::std::string process_name(program_invocation_short_name);
Brian Silvermanf665d692013-02-17 22:11:39 -080037
38 char thread_name_array[kThreadNameLength + 1];
39 if (prctl(PR_GET_NAME, thread_name_array) != 0) {
40 Die("prctl(PR_GET_NAME, %p) failed with %d: %s\n",
41 thread_name_array, errno, strerror(errno));
42 }
43 thread_name_array[sizeof(thread_name_array) - 1] = '\0';
Brian Silvermanab6615c2013-03-05 20:29:29 -080044 ::std::string thread_name(thread_name_array);
Brian Silvermanf665d692013-02-17 22:11:39 -080045
46 // If the first bunch of characters are the same.
47 // We cut off comparing at the shorter of the 2 strings because one or the
48 // other often ends up cut off.
49 if (strncmp(thread_name.c_str(), process_name.c_str(),
Brian Silvermanab6615c2013-03-05 20:29:29 -080050 ::std::min(thread_name.length(), process_name.length())) == 0) {
Brian Silvermanf665d692013-02-17 22:11:39 -080051 // This thread doesn't have an actual name.
52 return process_name;
53 }
54
55 return process_name + '.' + thread_name;
56}
57
Brian Silvermana6d1b562013-09-01 14:39:39 -070058static Queue *queue;
Brian Silvermanf665d692013-02-17 22:11:39 -080059
60} // namespace
61namespace internal {
62
63Context *Context::Get() {
64 if (my_context == NULL) {
65 my_context = new Context();
Brian Silvermanab6615c2013-03-05 20:29:29 -080066 my_context->name = GetMyName();
67 if (my_context->name.size() + 1 > sizeof(LogMessage::name)) {
68 Die("logging: process/thread name '%s' is too long\n",
69 my_context->name.c_str());
70 }
Brian Silvermanf665d692013-02-17 22:11:39 -080071 my_context->source = getpid();
72 }
73 return my_context;
74}
75
76void Context::Delete() {
77 delete my_context;
78 my_context = NULL;
79}
80
81} // namespace internal
82namespace atom {
83namespace {
84
Brian Silvermanab6615c2013-03-05 20:29:29 -080085class AtomQueueLogImplementation : public LogImplementation {
Brian Silvermanf665d692013-02-17 22:11:39 -080086 virtual void DoLog(log_level level, const char *format, va_list ap) {
Brian Silvermana6d1b562013-09-01 14:39:39 -070087 LogMessage *message = static_cast<LogMessage *>(queue->GetMessage());
Brian Silvermanf665d692013-02-17 22:11:39 -080088 if (message == NULL) {
89 LOG(FATAL, "queue get message failed\n");
90 }
91
92 internal::FillInMessage(level, format, ap, message);
93
94 Write(message);
95 }
96};
97
98} // namespace
99
100void Register() {
101 Init();
102
Brian Silvermana6d1b562013-09-01 14:39:39 -0700103 queue = Queue::Fetch("LoggingQueue", sizeof(LogMessage), 1323, 1500);
Brian Silvermanf665d692013-02-17 22:11:39 -0800104 if (queue == NULL) {
105 Die("logging: couldn't fetch queue\n");
106 }
107
Brian Silvermanab6615c2013-03-05 20:29:29 -0800108 AddImplementation(new AtomQueueLogImplementation());
Brian Silvermanf665d692013-02-17 22:11:39 -0800109}
110
111const LogMessage *ReadNext(int flags, int *index) {
Brian Silvermana6d1b562013-09-01 14:39:39 -0700112 return static_cast<const LogMessage *>(queue->ReadMessageIndex(flags, index));
Brian Silvermanf665d692013-02-17 22:11:39 -0800113}
114
115const LogMessage *ReadNext() {
Brian Silvermana6d1b562013-09-01 14:39:39 -0700116 return ReadNext(Queue::kBlock);
Brian Silvermanf665d692013-02-17 22:11:39 -0800117}
118
119const LogMessage *ReadNext(int flags) {
120 const LogMessage *r = NULL;
121 do {
Brian Silvermana6d1b562013-09-01 14:39:39 -0700122 r = static_cast<const LogMessage *>(queue->ReadMessage(flags));
Brian Silvermanf665d692013-02-17 22:11:39 -0800123 // not blocking means return a NULL if that's what it gets
Brian Silvermana6d1b562013-09-01 14:39:39 -0700124 } while ((flags & Queue::kBlock) && r == NULL);
Brian Silvermanf665d692013-02-17 22:11:39 -0800125 return r;
126}
127
128LogMessage *Get() {
Brian Silvermana6d1b562013-09-01 14:39:39 -0700129 return static_cast<LogMessage *>(queue->GetMessage());
Brian Silvermanf665d692013-02-17 22:11:39 -0800130}
131
132void Free(const LogMessage *msg) {
Brian Silvermana6d1b562013-09-01 14:39:39 -0700133 queue->FreeMessage(msg);
Brian Silvermanf665d692013-02-17 22:11:39 -0800134}
135
136void Write(LogMessage *msg) {
Brian Silvermana6d1b562013-09-01 14:39:39 -0700137 if (!queue->WriteMessage(msg, Queue::kOverride)) {
Brian Silvermanf665d692013-02-17 22:11:39 -0800138 LOG(FATAL, "writing failed");
139 }
140}
141
142} // namespace atom
143} // namespace logging
144} // namespace aos