blob: 9fa2baf653e3560b13bb0b6d13bdb45073fa385a [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;
26
27LogEvent::LogEvent(const log_msg& msg) {
28 init(msg);
29}
30
31LogEvent::LogEvent(int64_t timestampNs, android_log_event_list* reader) {
32 init(timestampNs, reader);
33}
34
35LogEvent::~LogEvent() {
36}
37
38/**
39 * The elements of each log event are stored as a vector of android_log_list_elements.
40 * The goal is to do as little preprocessing as possible, because we read a tiny fraction
41 * of the elements that are written to the log.
42 */
43void LogEvent::init(const log_msg& msg) {
44
45 android_log_event_list list(const_cast<log_msg&>(msg));
46 init(msg.entry_v1.sec * NS_PER_SEC + msg.entry_v1.nsec, &list);
47}
48
49void LogEvent::init(int64_t timestampNs, android_log_event_list* reader) {
50 mTimestampNs = timestampNs;
51 mTagId = reader->tag();
52
53 mElements.clear();
54 android_log_list_element elem;
55
56 // TODO: The log is actually structured inside one list. This is convenient
57 // because we'll be able to use it to put the attribution (WorkSource) block first
58 // without doing our own tagging scheme. Until that change is in, just drop the
59 // list-related log elements and the order we get there is our index-keyed data
60 // structure.
61 do {
62 elem = android_log_read_next(reader->context());
63 switch ((int)elem.type) {
64 case EVENT_TYPE_INT:
65 case EVENT_TYPE_FLOAT:
66 case EVENT_TYPE_STRING:
67 case EVENT_TYPE_LONG:
68 mElements.push_back(elem);
69 break;
70 case EVENT_TYPE_LIST:
71 break;
72 case EVENT_TYPE_LIST_STOP:
73 break;
74 case EVENT_TYPE_UNKNOWN:
75 break;
76 default:
77 break;
78 }
79 } while ((elem.type != EVENT_TYPE_UNKNOWN) && !elem.complete);
80}
81
82int64_t LogEvent::GetLong(size_t key, status_t* err) const {
83 if (key < 1 || (key - 1) >= mElements.size()) {
84 *err = BAD_INDEX;
85 return 0;
86 }
87 key--;
88 const android_log_list_element& elem = mElements[key];
89 if (elem.type == EVENT_TYPE_INT) {
90 return elem.data.int32;
91 } else if (elem.type == EVENT_TYPE_LONG) {
92 return elem.data.int64;
93 } else if (elem.type == EVENT_TYPE_FLOAT) {
94 return (int64_t)elem.data.float32;
95 } else {
96 *err = BAD_TYPE;
97 return 0;
98 }
99}
100
101const char* LogEvent::GetString(size_t key, status_t* err) const {
102 if (key < 1 || (key - 1) >= mElements.size()) {
103 *err = BAD_INDEX;
104 return NULL;
105 }
106 key--;
107 const android_log_list_element& elem = mElements[key];
108 if (elem.type != EVENT_TYPE_STRING) {
109 *err = BAD_TYPE;
110 return NULL;
111 }
112 return elem.data.string;
113}
114
115bool LogEvent::GetBool(size_t key, status_t* err) const {
116 if (key < 1 || (key - 1) >= mElements.size()) {
117 *err = BAD_INDEX;
118 return 0;
119 }
120 key--;
121 const android_log_list_element& elem = mElements[key];
122 if (elem.type == EVENT_TYPE_INT) {
123 return elem.data.int32 != 0;
124 } else if (elem.type == EVENT_TYPE_LONG) {
125 return elem.data.int64 != 0;
126 } else if (elem.type == EVENT_TYPE_FLOAT) {
127 return elem.data.float32 != 0;
128 } else {
129 *err = BAD_TYPE;
130 return 0;
131 }
132}
133
134float LogEvent::GetFloat(size_t key, status_t* err) const {
135 if (key < 1 || (key - 1) >= mElements.size()) {
136 *err = BAD_INDEX;
137 return 0;
138 }
139 key--;
140 const android_log_list_element& elem = mElements[key];
141 if (elem.type == EVENT_TYPE_INT) {
142 return (float)elem.data.int32;
143 } else if (elem.type == EVENT_TYPE_LONG) {
144 return (float)elem.data.int64;
145 } else if (elem.type == EVENT_TYPE_FLOAT) {
146 return elem.data.float32;
147 } else {
148 *err = BAD_TYPE;
149 return 0;
150 }
151}
152
153string LogEvent::ToString() const {
154 ostringstream result;
155 result << "{ " << mTimestampNs << " (" << mTagId << ")";
156 const size_t N = mElements.size();
157 for (size_t i=0; i<N; i++) {
158 result << " ";
159 result << (i + 1);
160 result << "->";
161 const android_log_list_element& elem = mElements[i];
162 if (elem.type == EVENT_TYPE_INT) {
163 result << elem.data.int32;
164 } else if (elem.type == EVENT_TYPE_LONG) {
165 result << elem.data.int64;
166 } else if (elem.type == EVENT_TYPE_FLOAT) {
167 result << elem.data.float32;
168 } else if (elem.type == EVENT_TYPE_STRING) {
169 result << elem.data.string;
170 }
171 }
172 result << " }";
173 return result.str();
174}
175
176void LogEvent::ToProto(EventMetricData* out) const {
177 // TODO: Implement this when we have the ProtoOutputStream version.
178
179 // set timestamp of the event.
180 out->set_timestamp_nanos(mTimestampNs);
181
182 // uint64_t token = proto->StartObject(EventMetricData.FIELD);
183 const size_t N = mElements.size();
184 for (size_t i=0; i<N; i++) {
185 const int key = i + 1;
186
187 const android_log_list_element& elem = mElements[i];
188 if (elem.type == EVENT_TYPE_INT) {
189 // proto->Write(key, elem.data.int32);
190 } else if (elem.type == EVENT_TYPE_LONG) {
191 // proto->Write(key, elem.data.int64);
192 } else if (elem.type == EVENT_TYPE_FLOAT) {
193 // proto->Write(key, elem.data.float32);
194 } else if (elem.type == EVENT_TYPE_STRING) {
195 // proto->Write(key, elem.data.string);
196 }
197 }
198
199 //proto->EndObject(token);
200}
201
202} // namespace statsd
203} // namespace os
204} // namespace android