blob: 9fa2baf653e3560b13bb0b6d13bdb45073fa385a [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "logd/LogEvent.h"
#include <sstream>
namespace android {
namespace os {
namespace statsd {
using std::ostringstream;
LogEvent::LogEvent(const log_msg& msg) {
init(msg);
}
LogEvent::LogEvent(int64_t timestampNs, android_log_event_list* reader) {
init(timestampNs, reader);
}
LogEvent::~LogEvent() {
}
/**
* The elements of each log event are stored as a vector of android_log_list_elements.
* The goal is to do as little preprocessing as possible, because we read a tiny fraction
* of the elements that are written to the log.
*/
void LogEvent::init(const log_msg& msg) {
android_log_event_list list(const_cast<log_msg&>(msg));
init(msg.entry_v1.sec * NS_PER_SEC + msg.entry_v1.nsec, &list);
}
void LogEvent::init(int64_t timestampNs, android_log_event_list* reader) {
mTimestampNs = timestampNs;
mTagId = reader->tag();
mElements.clear();
android_log_list_element elem;
// TODO: The log is actually structured inside one list. This is convenient
// because we'll be able to use it to put the attribution (WorkSource) block first
// without doing our own tagging scheme. Until that change is in, just drop the
// list-related log elements and the order we get there is our index-keyed data
// structure.
do {
elem = android_log_read_next(reader->context());
switch ((int)elem.type) {
case EVENT_TYPE_INT:
case EVENT_TYPE_FLOAT:
case EVENT_TYPE_STRING:
case EVENT_TYPE_LONG:
mElements.push_back(elem);
break;
case EVENT_TYPE_LIST:
break;
case EVENT_TYPE_LIST_STOP:
break;
case EVENT_TYPE_UNKNOWN:
break;
default:
break;
}
} while ((elem.type != EVENT_TYPE_UNKNOWN) && !elem.complete);
}
int64_t LogEvent::GetLong(size_t key, status_t* err) const {
if (key < 1 || (key - 1) >= mElements.size()) {
*err = BAD_INDEX;
return 0;
}
key--;
const android_log_list_element& elem = mElements[key];
if (elem.type == EVENT_TYPE_INT) {
return elem.data.int32;
} else if (elem.type == EVENT_TYPE_LONG) {
return elem.data.int64;
} else if (elem.type == EVENT_TYPE_FLOAT) {
return (int64_t)elem.data.float32;
} else {
*err = BAD_TYPE;
return 0;
}
}
const char* LogEvent::GetString(size_t key, status_t* err) const {
if (key < 1 || (key - 1) >= mElements.size()) {
*err = BAD_INDEX;
return NULL;
}
key--;
const android_log_list_element& elem = mElements[key];
if (elem.type != EVENT_TYPE_STRING) {
*err = BAD_TYPE;
return NULL;
}
return elem.data.string;
}
bool LogEvent::GetBool(size_t key, status_t* err) const {
if (key < 1 || (key - 1) >= mElements.size()) {
*err = BAD_INDEX;
return 0;
}
key--;
const android_log_list_element& elem = mElements[key];
if (elem.type == EVENT_TYPE_INT) {
return elem.data.int32 != 0;
} else if (elem.type == EVENT_TYPE_LONG) {
return elem.data.int64 != 0;
} else if (elem.type == EVENT_TYPE_FLOAT) {
return elem.data.float32 != 0;
} else {
*err = BAD_TYPE;
return 0;
}
}
float LogEvent::GetFloat(size_t key, status_t* err) const {
if (key < 1 || (key - 1) >= mElements.size()) {
*err = BAD_INDEX;
return 0;
}
key--;
const android_log_list_element& elem = mElements[key];
if (elem.type == EVENT_TYPE_INT) {
return (float)elem.data.int32;
} else if (elem.type == EVENT_TYPE_LONG) {
return (float)elem.data.int64;
} else if (elem.type == EVENT_TYPE_FLOAT) {
return elem.data.float32;
} else {
*err = BAD_TYPE;
return 0;
}
}
string LogEvent::ToString() const {
ostringstream result;
result << "{ " << mTimestampNs << " (" << mTagId << ")";
const size_t N = mElements.size();
for (size_t i=0; i<N; i++) {
result << " ";
result << (i + 1);
result << "->";
const android_log_list_element& elem = mElements[i];
if (elem.type == EVENT_TYPE_INT) {
result << elem.data.int32;
} else if (elem.type == EVENT_TYPE_LONG) {
result << elem.data.int64;
} else if (elem.type == EVENT_TYPE_FLOAT) {
result << elem.data.float32;
} else if (elem.type == EVENT_TYPE_STRING) {
result << elem.data.string;
}
}
result << " }";
return result.str();
}
void LogEvent::ToProto(EventMetricData* out) const {
// TODO: Implement this when we have the ProtoOutputStream version.
// set timestamp of the event.
out->set_timestamp_nanos(mTimestampNs);
// uint64_t token = proto->StartObject(EventMetricData.FIELD);
const size_t N = mElements.size();
for (size_t i=0; i<N; i++) {
const int key = i + 1;
const android_log_list_element& elem = mElements[i];
if (elem.type == EVENT_TYPE_INT) {
// proto->Write(key, elem.data.int32);
} else if (elem.type == EVENT_TYPE_LONG) {
// proto->Write(key, elem.data.int64);
} else if (elem.type == EVENT_TYPE_FLOAT) {
// proto->Write(key, elem.data.float32);
} else if (elem.type == EVENT_TYPE_STRING) {
// proto->Write(key, elem.data.string);
}
}
//proto->EndObject(token);
}
} // namespace statsd
} // namespace os
} // namespace android