blob: fb992c11aad76acce824aa598f2e14106f878f78 [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>
20
21namespace android {
22namespace os {
23namespace statsd {
24
25using std::ostringstream;
David Chen1481fe12017-10-16 13:16:34 -070026using std::string;
Joe Onoratoc4dfae52017-10-17 23:38:21 -070027
David Chen1481fe12017-10-16 13:16:34 -070028// We need to keep a copy of the android_log_event_list owned by this instance so that the char*
29// for strings is not cleared before we can read them.
30LogEvent::LogEvent(log_msg msg) : mList(msg) {
31 init(msg.entry_v1.sec * NS_PER_SEC + msg.entry_v1.nsec, &mList);
Joe Onoratoc4dfae52017-10-17 23:38:21 -070032}
33
David Chen1481fe12017-10-16 13:16:34 -070034LogEvent::LogEvent(int tag) : mList(tag) {
Joe Onoratoc4dfae52017-10-17 23:38:21 -070035}
36
37LogEvent::~LogEvent() {
38}
39
David Chen1481fe12017-10-16 13:16:34 -070040void LogEvent::init() {
41 mList.convert_to_reader();
42 init(mTimestampNs, &mList);
43}
44
Joe Onoratoc4dfae52017-10-17 23:38:21 -070045/**
46 * The elements of each log event are stored as a vector of android_log_list_elements.
47 * The goal is to do as little preprocessing as possible, because we read a tiny fraction
48 * of the elements that are written to the log.
49 */
Joe Onoratoc4dfae52017-10-17 23:38:21 -070050void LogEvent::init(int64_t timestampNs, android_log_event_list* reader) {
51 mTimestampNs = timestampNs;
52 mTagId = reader->tag();
53
54 mElements.clear();
55 android_log_list_element elem;
56
57 // TODO: The log is actually structured inside one list. This is convenient
58 // because we'll be able to use it to put the attribution (WorkSource) block first
59 // without doing our own tagging scheme. Until that change is in, just drop the
60 // list-related log elements and the order we get there is our index-keyed data
61 // structure.
62 do {
63 elem = android_log_read_next(reader->context());
64 switch ((int)elem.type) {
65 case EVENT_TYPE_INT:
66 case EVENT_TYPE_FLOAT:
67 case EVENT_TYPE_STRING:
68 case EVENT_TYPE_LONG:
69 mElements.push_back(elem);
70 break;
71 case EVENT_TYPE_LIST:
72 break;
73 case EVENT_TYPE_LIST_STOP:
74 break;
75 case EVENT_TYPE_UNKNOWN:
76 break;
77 default:
78 break;
79 }
80 } while ((elem.type != EVENT_TYPE_UNKNOWN) && !elem.complete);
81}
82
David Chen1481fe12017-10-16 13:16:34 -070083android_log_event_list* LogEvent::GetAndroidLogEventList() {
84 return &mList;
85}
86
Joe Onoratoc4dfae52017-10-17 23:38:21 -070087int64_t LogEvent::GetLong(size_t key, status_t* err) const {
88 if (key < 1 || (key - 1) >= mElements.size()) {
89 *err = BAD_INDEX;
90 return 0;
91 }
92 key--;
93 const android_log_list_element& elem = mElements[key];
94 if (elem.type == EVENT_TYPE_INT) {
95 return elem.data.int32;
96 } else if (elem.type == EVENT_TYPE_LONG) {
97 return elem.data.int64;
98 } else if (elem.type == EVENT_TYPE_FLOAT) {
99 return (int64_t)elem.data.float32;
100 } else {
101 *err = BAD_TYPE;
102 return 0;
103 }
104}
105
106const char* LogEvent::GetString(size_t key, status_t* err) const {
107 if (key < 1 || (key - 1) >= mElements.size()) {
108 *err = BAD_INDEX;
109 return NULL;
110 }
111 key--;
112 const android_log_list_element& elem = mElements[key];
113 if (elem.type != EVENT_TYPE_STRING) {
114 *err = BAD_TYPE;
115 return NULL;
116 }
David Chen1481fe12017-10-16 13:16:34 -0700117 // Need to add the '/0' at the end by specifying the length of the string.
118 return string(elem.data.string, elem.len).c_str();
Joe Onoratoc4dfae52017-10-17 23:38:21 -0700119}
120
121bool LogEvent::GetBool(size_t key, status_t* err) const {
122 if (key < 1 || (key - 1) >= mElements.size()) {
123 *err = BAD_INDEX;
124 return 0;
125 }
126 key--;
127 const android_log_list_element& elem = mElements[key];
128 if (elem.type == EVENT_TYPE_INT) {
129 return elem.data.int32 != 0;
130 } else if (elem.type == EVENT_TYPE_LONG) {
131 return elem.data.int64 != 0;
132 } else if (elem.type == EVENT_TYPE_FLOAT) {
133 return elem.data.float32 != 0;
134 } else {
135 *err = BAD_TYPE;
136 return 0;
137 }
138}
139
140float LogEvent::GetFloat(size_t key, status_t* err) const {
141 if (key < 1 || (key - 1) >= mElements.size()) {
142 *err = BAD_INDEX;
143 return 0;
144 }
145 key--;
146 const android_log_list_element& elem = mElements[key];
147 if (elem.type == EVENT_TYPE_INT) {
148 return (float)elem.data.int32;
149 } else if (elem.type == EVENT_TYPE_LONG) {
150 return (float)elem.data.int64;
151 } else if (elem.type == EVENT_TYPE_FLOAT) {
152 return elem.data.float32;
153 } else {
154 *err = BAD_TYPE;
155 return 0;
156 }
157}
158
Yao Chen729093d2017-10-16 10:33:26 -0700159KeyValuePair LogEvent::GetKeyValueProto(size_t key) const {
160 KeyValuePair pair;
161 pair.set_key(key);
162 // If the value is not valid, return the KeyValuePair without assigning the value.
163 // Caller can detect the error by checking the enum for "one of" proto type.
164 if (key < 1 || (key - 1) >= mElements.size()) {
165 return pair;
166 }
167 key--;
168
169 const android_log_list_element& elem = mElements[key];
170 if (elem.type == EVENT_TYPE_INT) {
171 pair.set_value_int(elem.data.int32);
172 } else if (elem.type == EVENT_TYPE_LONG) {
173 pair.set_value_int(elem.data.int64);
174 } else if (elem.type == EVENT_TYPE_STRING) {
175 pair.set_value_str(elem.data.string);
176 } else if (elem.type == EVENT_TYPE_FLOAT) {
177 pair.set_value_float(elem.data.float32);
178 }
179 return pair;
180}
181
Joe Onoratoc4dfae52017-10-17 23:38:21 -0700182string LogEvent::ToString() const {
183 ostringstream result;
184 result << "{ " << mTimestampNs << " (" << mTagId << ")";
185 const size_t N = mElements.size();
186 for (size_t i=0; i<N; i++) {
187 result << " ";
188 result << (i + 1);
189 result << "->";
190 const android_log_list_element& elem = mElements[i];
191 if (elem.type == EVENT_TYPE_INT) {
192 result << elem.data.int32;
193 } else if (elem.type == EVENT_TYPE_LONG) {
194 result << elem.data.int64;
195 } else if (elem.type == EVENT_TYPE_FLOAT) {
196 result << elem.data.float32;
197 } else if (elem.type == EVENT_TYPE_STRING) {
David Chen1481fe12017-10-16 13:16:34 -0700198 // Need to add the '/0' at the end by specifying the length of the string.
199 result << string(elem.data.string, elem.len).c_str();
Joe Onoratoc4dfae52017-10-17 23:38:21 -0700200 }
201 }
202 result << " }";
203 return result.str();
204}
205
206void LogEvent::ToProto(EventMetricData* out) const {
207 // TODO: Implement this when we have the ProtoOutputStream version.
208
209 // set timestamp of the event.
210 out->set_timestamp_nanos(mTimestampNs);
211
212 // uint64_t token = proto->StartObject(EventMetricData.FIELD);
213 const size_t N = mElements.size();
214 for (size_t i=0; i<N; i++) {
215 const int key = i + 1;
216
217 const android_log_list_element& elem = mElements[i];
218 if (elem.type == EVENT_TYPE_INT) {
219 // proto->Write(key, elem.data.int32);
220 } else if (elem.type == EVENT_TYPE_LONG) {
221 // proto->Write(key, elem.data.int64);
222 } else if (elem.type == EVENT_TYPE_FLOAT) {
223 // proto->Write(key, elem.data.float32);
224 } else if (elem.type == EVENT_TYPE_STRING) {
225 // proto->Write(key, elem.data.string);
226 }
227 }
228
229 //proto->EndObject(token);
230}
231
232} // namespace statsd
233} // namespace os
234} // namespace android