Skip to content

Commit ec39a3f

Browse files
author
Tom Cherry
committed
logd: record and replay log messages
To profile different log buffer types and configuration, this change adds the ability to record log messages and adds a tool that will replay those log messages through different log buffer implementations and collect stats about the execution. Test: log messages replay correctly Change-Id: I0dc6c545b782fa7732e325dde109c496b137d0dd
1 parent 1270608 commit ec39a3f

8 files changed

+694
-4
lines changed

logd/Android.bp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,3 +180,23 @@ cc_test {
180180
"vts10",
181181
],
182182
}
183+
184+
cc_binary {
185+
name: "replay_messages",
186+
defaults: ["logd_defaults"],
187+
host_supported: true,
188+
189+
srcs: [
190+
"ReplayMessages.cpp",
191+
],
192+
193+
static_libs: [
194+
"libbase",
195+
"libcutils",
196+
"liblog",
197+
"liblogd",
198+
"libselinux",
199+
"libz",
200+
"libzstd",
201+
],
202+
}

logd/LogStatistics.cpp

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,10 @@
2626
#include <unistd.h>
2727

2828
#include <list>
29+
#include <vector>
2930

3031
#include <android-base/logging.h>
32+
#include <android-base/strings.h>
3133
#include <private/android_logger.h>
3234

3335
#include "LogBufferElement.h"
@@ -61,7 +63,8 @@ static std::string TagNameKey(const LogStatisticsElement& element) {
6163
return std::string(msg, len);
6264
}
6365

64-
LogStatistics::LogStatistics(bool enable_statistics, bool track_total_size)
66+
LogStatistics::LogStatistics(bool enable_statistics, bool track_total_size,
67+
std::optional<log_time> start_time)
6568
: enable(enable_statistics), track_total_size_(track_total_size) {
6669
log_time now(CLOCK_REALTIME);
6770
log_id_for_each(id) {
@@ -70,8 +73,13 @@ LogStatistics::LogStatistics(bool enable_statistics, bool track_total_size)
7073
mDroppedElements[id] = 0;
7174
mSizesTotal[id] = 0;
7275
mElementsTotal[id] = 0;
73-
mOldest[id] = now;
74-
mNewest[id] = now;
76+
if (start_time) {
77+
mOldest[id] = *start_time;
78+
mNewest[id] = *start_time;
79+
} else {
80+
mOldest[id] = now;
81+
mNewest[id] = now;
82+
}
7583
mNewestDropped[id] = now;
7684
}
7785
}
@@ -784,6 +792,31 @@ std::string LogStatistics::FormatTable(const LogHashtable<TKey, TEntry>& table,
784792
return output;
785793
}
786794

795+
std::string LogStatistics::ReportInteresting() const {
796+
auto lock = std::lock_guard{lock_};
797+
798+
std::vector<std::string> items;
799+
800+
log_id_for_each(i) { items.emplace_back(std::to_string(mElements[i])); }
801+
802+
log_id_for_each(i) { items.emplace_back(std::to_string(mSizes[i])); }
803+
804+
log_id_for_each(i) {
805+
items.emplace_back(std::to_string(overhead_[i] ? *overhead_[i] : mSizes[i]));
806+
}
807+
808+
log_id_for_each(i) {
809+
uint64_t oldest = mOldest[i].msec() / 1000;
810+
uint64_t newest = mNewest[i].msec() / 1000;
811+
812+
int span = newest - oldest;
813+
814+
items.emplace_back(std::to_string(span));
815+
}
816+
817+
return android::base::Join(items, ",");
818+
}
819+
787820
std::string LogStatistics::Format(uid_t uid, pid_t pid, unsigned int logMask) const {
788821
auto lock = std::lock_guard{lock_};
789822

logd/LogStatistics.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -515,7 +515,8 @@ class LogStatistics {
515515
}
516516

517517
public:
518-
LogStatistics(bool enable_statistics, bool track_total_size);
518+
LogStatistics(bool enable_statistics, bool track_total_size,
519+
std::optional<log_time> start_time = {});
519520

520521
void AddTotal(log_id_t log_id, uint16_t size) EXCLUDES(lock_);
521522

@@ -556,6 +557,7 @@ class LogStatistics {
556557
return SizesTotal;
557558
}
558559

560+
std::string ReportInteresting() const EXCLUDES(lock_);
559561
std::string Format(uid_t uid, pid_t pid, unsigned int logMask) const EXCLUDES(lock_);
560562

561563
const char* PidToName(pid_t pid) const EXCLUDES(lock_);

logd/README.replay.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
logd can record and replay log messages for offline analysis.
2+
3+
Recording Messages
4+
------------------
5+
6+
logd has a `RecordingLogBuffer` buffer that records messages to /data/misc/logd/recorded-messages.
7+
It stores messages in memory until that file is accessible, in order to capture all messages since
8+
the beginning of boot. It is only meant for logging developers to use and must be manually enabled
9+
in by adding `RecordingLogBuffer.cpp` to `Android.bp` and setting
10+
`log_buffer = new SimpleLogBuffer(&reader_list, &log_tags, &log_statistics);` in `main.cpp`.
11+
12+
Recording messages may delay the Log() function from completing and it is highly recommended to make
13+
the logd socket in `liblog` blocking, by removing `SOCK_NONBLOCK` from the `socket()` call in
14+
`liblog/logd_writer.cpp`.
15+
16+
Replaying Messages
17+
------------------
18+
19+
Recorded messages can be replayed offline with the `replay_messages` tool. It runs on host and
20+
device and supports the following options:
21+
22+
1. `interesting` - this prints 'interesting' statistics for each of the log buffer types (simple,
23+
chatty, serialized). The statistics are:
24+
1. Log Entry Count
25+
2. Size (the uncompressed size of the log messages in bytes)
26+
3. Overhead (the total cost of the log messages in memory in bytes)
27+
4. Range (the range of time that the logs cover in seconds)
28+
2. `memory_usage BUFFER_TYPE` - this prints the memory usage (sum of private dirty pages of the
29+
`replay_messages` process). Note that the input file is mmap()'ed as RO/Shared so it does not
30+
appear in these dirty pages, and a baseline is taken before allocating the log buffers, so only
31+
their contributions are measured. The tool outputs the memory usage every 100,000 messages.
32+
3. `latency BUFFER_TYPE` - this prints statistics of the latency of the Log() function for the given
33+
buffer type. It specifically prints the 1st, 2nd, and 3rd quartiles; the 95th, 99th, and 99.99th
34+
percentiles; and the maximum latency.
35+
4. `print_logs BUFFER_TYPE [buffers] [print_point]` - this prints the logs as processed by the given
36+
buffer_type from the buffers specified by `buffers` starting after the number of logs specified by
37+
`print_point` have been logged. This acts as if a user called `logcat` immediately after the
38+
specified logs have been logged, which is particularly useful since it will show the chatty
39+
pruning messages at that point. It additionally prints the statistics from `logcat -S` after the
40+
logs.
41+
`buffers` is a comma separated list of the numeric buffer id values from `<android/log.h>`. For
42+
example, `0,1,3` represents the main, radio, and system buffers. It can can also be `all`.
43+
`print_point` is an positive integer. If it is unspecified, logs are printed after the entire
44+
input file is consumed.
45+
5. `nothing BUFFER_TYPE` - this does nothing other than read the input file and call Log() for the
46+
given buffer type. This is used for profiling CPU usage of strictly the log buffer.

logd/RecordedLogMessage.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* Copyright (C) 2020 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+
#pragma once
18+
19+
#include <inttypes.h>
20+
21+
#include <log/log_time.h>
22+
23+
struct __attribute__((packed)) RecordedLogMessage {
24+
uint32_t uid;
25+
uint32_t pid;
26+
uint32_t tid;
27+
log_time realtime;
28+
uint16_t msg_len;
29+
uint8_t log_id;
30+
};

logd/RecordingLogBuffer.cpp

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*
2+
* Copyright (C) 2020 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 "RecordingLogBuffer.h"
18+
19+
#include <android-base/file.h>
20+
21+
static void WriteLogMessage(int fd, const RecordedLogMessage& meta, const std::string& msg) {
22+
android::base::WriteFully(fd, &meta, sizeof(meta));
23+
android::base::WriteFully(fd, msg.c_str(), meta.msg_len);
24+
}
25+
26+
void RecordingLogBuffer::RecordLogMessage(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid,
27+
pid_t tid, const char* msg, uint16_t len) {
28+
auto lock = std::lock_guard{lock_};
29+
if (len > LOGGER_ENTRY_MAX_PAYLOAD) {
30+
len = LOGGER_ENTRY_MAX_PAYLOAD;
31+
}
32+
33+
RecordedLogMessage recorded_log_message = {
34+
.uid = uid,
35+
.pid = static_cast<uint32_t>(pid),
36+
.tid = static_cast<uint32_t>(tid),
37+
.realtime = realtime,
38+
.msg_len = len,
39+
.log_id = static_cast<uint8_t>(log_id),
40+
};
41+
42+
if (!fd_.ok()) {
43+
fd_.reset(open("/data/misc/logd/recorded-messages",
44+
O_WRONLY | O_CREAT | O_APPEND | O_CLOEXEC, 0666));
45+
if (!fd_.ok()) {
46+
since_boot_messages_.emplace_back(recorded_log_message, std::string(msg, len));
47+
return;
48+
} else {
49+
for (const auto& [meta, msg] : since_boot_messages_) {
50+
WriteLogMessage(fd_.get(), meta, msg);
51+
}
52+
}
53+
}
54+
55+
WriteLogMessage(fd_.get(), recorded_log_message, std::string(msg, len));
56+
}
57+
58+
int RecordingLogBuffer::Log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, pid_t tid,
59+
const char* msg, uint16_t len) {
60+
RecordLogMessage(log_id, realtime, uid, pid, tid, msg, len);
61+
return SimpleLogBuffer::Log(log_id, realtime, uid, pid, tid, msg, len);
62+
}

logd/RecordingLogBuffer.h

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright (C) 2020 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+
#pragma once
18+
19+
#include "SimpleLogBuffer.h"
20+
21+
#include <string>
22+
#include <tuple>
23+
#include <vector>
24+
25+
#include <android-base/unique_fd.h>
26+
27+
#include "RecordedLogMessage.h"
28+
29+
class RecordingLogBuffer : public SimpleLogBuffer {
30+
public:
31+
RecordingLogBuffer(LogReaderList* reader_list, LogTags* tags, LogStatistics* stats)
32+
: SimpleLogBuffer(reader_list, tags, stats) {}
33+
34+
int Log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, pid_t tid, const char* msg,
35+
uint16_t len) override;
36+
37+
private:
38+
void RecordLogMessage(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, pid_t tid,
39+
const char* msg, uint16_t len);
40+
41+
std::vector<std::pair<RecordedLogMessage, std::string>> since_boot_messages_;
42+
android::base::unique_fd fd_;
43+
};

0 commit comments

Comments
 (0)