blob: 1a039f6d61c56cfd1b84f4ccf38189445288a9fa [file] [log] [blame]
Joe Onoratoc4dfae52017-10-17 23:38:21 -07001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "logd/LogEvent.h"
18
19#include <sstream>
Yao Chen5110bed2017-10-23 12:50:02 -070020#include "stats_util.h"
Joe Onoratoc4dfae52017-10-17 23:38:21 -070021
22namespace android {
23namespace os {
24namespace statsd {
25
26using std::ostringstream;
David Chen1481fe12017-10-16 13:16:34 -070027using std::string;
Yao Chen5110bed2017-10-23 12:50:02 -070028using android::util::ProtoOutputStream;
Joe Onoratoc4dfae52017-10-17 23:38:21 -070029
David Chen1481fe12017-10-16 13:16:34 -070030// We need to keep a copy of the android_log_event_list owned by this instance so that the char*
31// for strings is not cleared before we can read them.
32LogEvent::LogEvent(log_msg msg) : mList(msg) {
33 init(msg.entry_v1.sec * NS_PER_SEC + msg.entry_v1.nsec, &mList);
Joe Onoratoc4dfae52017-10-17 23:38:21 -070034}
35
David Chen1481fe12017-10-16 13:16:34 -070036LogEvent::LogEvent(int tag) : mList(tag) {
Joe Onoratoc4dfae52017-10-17 23:38:21 -070037}
38
39LogEvent::~LogEvent() {
40}
41
David Chen1481fe12017-10-16 13:16:34 -070042void LogEvent::init() {
43 mList.convert_to_reader();
44 init(mTimestampNs, &mList);
45}
46
Joe Onoratoc4dfae52017-10-17 23:38:21 -070047/**
48 * The elements of each log event are stored as a vector of android_log_list_elements.
49 * The goal is to do as little preprocessing as possible, because we read a tiny fraction
50 * of the elements that are written to the log.
51 */
Joe Onoratoc4dfae52017-10-17 23:38:21 -070052void LogEvent::init(int64_t timestampNs, android_log_event_list* reader) {
53 mTimestampNs = timestampNs;
54 mTagId = reader->tag();
55
56 mElements.clear();
57 android_log_list_element elem;
58
59 // TODO: The log is actually structured inside one list. This is convenient
60 // because we'll be able to use it to put the attribution (WorkSource) block first
61 // without doing our own tagging scheme. Until that change is in, just drop the
62 // list-related log elements and the order we get there is our index-keyed data
63 // structure.
64 do {
65 elem = android_log_read_next(reader->context());
66 switch ((int)elem.type) {
67 case EVENT_TYPE_INT:
68 case EVENT_TYPE_FLOAT:
69 case EVENT_TYPE_STRING:
70 case EVENT_TYPE_LONG:
71 mElements.push_back(elem);
72 break;
73 case EVENT_TYPE_LIST:
74 break;
75 case EVENT_TYPE_LIST_STOP:
76 break;
77 case EVENT_TYPE_UNKNOWN:
78 break;
79 default:
80 break;
81 }
82 } while ((elem.type != EVENT_TYPE_UNKNOWN) && !elem.complete);
83}
84
David Chen1481fe12017-10-16 13:16:34 -070085android_log_event_list* LogEvent::GetAndroidLogEventList() {
86 return &mList;
87}
88
Joe Onoratoc4dfae52017-10-17 23:38:21 -070089int64_t LogEvent::GetLong(size_t key, status_t* err) const {
90 if (key < 1 || (key - 1) >= mElements.size()) {
91 *err = BAD_INDEX;
92 return 0;
93 }
94 key--;
95 const android_log_list_element& elem = mElements[key];
96 if (elem.type == EVENT_TYPE_INT) {
97 return elem.data.int32;
98 } else if (elem.type == EVENT_TYPE_LONG) {
99 return elem.data.int64;
100 } else if (elem.type == EVENT_TYPE_FLOAT) {
101 return (int64_t)elem.data.float32;
102 } else {
103 *err = BAD_TYPE;
104 return 0;
105 }
106}
107
108const char* LogEvent::GetString(size_t key, status_t* err) const {
109 if (key < 1 || (key - 1) >= mElements.size()) {
110 *err = BAD_INDEX;
111 return NULL;
112 }
113 key--;
114 const android_log_list_element& elem = mElements[key];
115 if (elem.type != EVENT_TYPE_STRING) {
116 *err = BAD_TYPE;
117 return NULL;
118 }
David Chen1481fe12017-10-16 13:16:34 -0700119 // Need to add the '/0' at the end by specifying the length of the string.
120 return string(elem.data.string, elem.len).c_str();
Joe Onoratoc4dfae52017-10-17 23:38:21 -0700121}
122
123bool LogEvent::GetBool(size_t key, status_t* err) const {
124 if (key < 1 || (key - 1) >= mElements.size()) {
125 *err = BAD_INDEX;
126 return 0;
127 }
128 key--;
129 const android_log_list_element& elem = mElements[key];
130 if (elem.type == EVENT_TYPE_INT) {
131 return elem.data.int32 != 0;
132 } else if (elem.type == EVENT_TYPE_LONG) {
133 return elem.data.int64 != 0;
134 } else if (elem.type == EVENT_TYPE_FLOAT) {
135 return elem.data.float32 != 0;
136 } else {
137 *err = BAD_TYPE;
138 return 0;
139 }
140}
141
142float LogEvent::GetFloat(size_t key, status_t* err) const {
143 if (key < 1 || (key - 1) >= mElements.size()) {
144 *err = BAD_INDEX;
145 return 0;
146 }
147 key--;
148 const android_log_list_element& elem = mElements[key];
149 if (elem.type == EVENT_TYPE_INT) {
150 return (float)elem.data.int32;
151 } else if (elem.type == EVENT_TYPE_LONG) {
152 return (float)elem.data.int64;
153 } else if (elem.type == EVENT_TYPE_FLOAT) {
154 return elem.data.float32;
155 } else {
156 *err = BAD_TYPE;
157 return 0;
158 }
159}
160
Yao Chen729093d2017-10-16 10:33:26 -0700161KeyValuePair LogEvent::GetKeyValueProto(size_t key) const {
162 KeyValuePair pair;
163 pair.set_key(key);
164 // If the value is not valid, return the KeyValuePair without assigning the value.
165 // Caller can detect the error by checking the enum for "one of" proto type.
166 if (key < 1 || (key - 1) >= mElements.size()) {
167 return pair;
168 }
169 key--;
170
171 const android_log_list_element& elem = mElements[key];
172 if (elem.type == EVENT_TYPE_INT) {
173 pair.set_value_int(elem.data.int32);
174 } else if (elem.type == EVENT_TYPE_LONG) {
175 pair.set_value_int(elem.data.int64);
176 } else if (elem.type == EVENT_TYPE_STRING) {
177 pair.set_value_str(elem.data.string);
178 } else if (elem.type == EVENT_TYPE_FLOAT) {
179 pair.set_value_float(elem.data.float32);
180 }
181 return pair;
182}
183
Joe Onoratoc4dfae52017-10-17 23:38:21 -0700184string LogEvent::ToString() const {
185 ostringstream result;
186 result << "{ " << mTimestampNs << " (" << mTagId << ")";
187 const size_t N = mElements.size();
188 for (size_t i=0; i<N; i++) {
189 result << " ";
190 result << (i + 1);
191 result << "->";
192 const android_log_list_element& elem = mElements[i];
193 if (elem.type == EVENT_TYPE_INT) {
194 result << elem.data.int32;
195 } else if (elem.type == EVENT_TYPE_LONG) {
196 result << elem.data.int64;
197 } else if (elem.type == EVENT_TYPE_FLOAT) {
198 result << elem.data.float32;
199 } else if (elem.type == EVENT_TYPE_STRING) {
David Chen1481fe12017-10-16 13:16:34 -0700200 // Need to add the '/0' at the end by specifying the length of the string.
201 result << string(elem.data.string, elem.len).c_str();
Joe Onoratoc4dfae52017-10-17 23:38:21 -0700202 }
203 }
204 result << " }";
205 return result.str();
206}
207
Yao Chen5110bed2017-10-23 12:50:02 -0700208void LogEvent::ToProto(ProtoOutputStream& proto) const {
209 long long atomToken = proto.start(TYPE_MESSAGE + mTagId);
Joe Onoratoc4dfae52017-10-17 23:38:21 -0700210 const size_t N = mElements.size();
211 for (size_t i=0; i<N; i++) {
212 const int key = i + 1;
213
214 const android_log_list_element& elem = mElements[i];
215 if (elem.type == EVENT_TYPE_INT) {
Yao Chen5110bed2017-10-23 12:50:02 -0700216 proto.write(TYPE_INT32 + key, elem.data.int32);
Joe Onoratoc4dfae52017-10-17 23:38:21 -0700217 } else if (elem.type == EVENT_TYPE_LONG) {
Yao Chen5110bed2017-10-23 12:50:02 -0700218 proto.write(TYPE_INT64 + key, (long long)elem.data.int64);
Joe Onoratoc4dfae52017-10-17 23:38:21 -0700219 } else if (elem.type == EVENT_TYPE_FLOAT) {
Yao Chen5110bed2017-10-23 12:50:02 -0700220 proto.write(TYPE_FLOAT + key, elem.data.float32);
Joe Onoratoc4dfae52017-10-17 23:38:21 -0700221 } else if (elem.type == EVENT_TYPE_STRING) {
Yao Chen5110bed2017-10-23 12:50:02 -0700222 proto.write(TYPE_STRING + key, elem.data.string);
Joe Onoratoc4dfae52017-10-17 23:38:21 -0700223 }
224 }
Yao Chen5110bed2017-10-23 12:50:02 -0700225 proto.end(atomToken);
Joe Onoratoc4dfae52017-10-17 23:38:21 -0700226}
227
228} // namespace statsd
229} // namespace os
230} // namespace android