diff options
22 files changed, 132 insertions, 9 deletions
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp index edc9f2ce6b3c..3e71b5368134 100644 --- a/cmds/statsd/src/StatsLogProcessor.cpp +++ b/cmds/statsd/src/StatsLogProcessor.cpp @@ -196,6 +196,14 @@ size_t StatsLogProcessor::GetMetricsSize(const ConfigKey& key) const { return it->second->byteSize(); } +void StatsLogProcessor::dumpStates(FILE* out, bool verbose) { + std::lock_guard<std::mutex> lock(mMetricsMutex); + fprintf(out, "MetricsManager count: %lu\n", (unsigned long)mMetricsManagers.size()); + for (auto metricsManager : mMetricsManagers) { + metricsManager.second->dumpStates(out, verbose); + } +} + void StatsLogProcessor::onDumpReport(const ConfigKey& key, const uint64_t& dumpTimeStampNs, ConfigMetricsReportList* report) { std::lock_guard<std::mutex> lock(mMetricsMutex); diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h index fb85aa837242..c19ff63e2858 100644 --- a/cmds/statsd/src/StatsLogProcessor.h +++ b/cmds/statsd/src/StatsLogProcessor.h @@ -61,6 +61,8 @@ public: return mUidMap; } + void dumpStates(FILE* out, bool verbose); + private: mutable mutex mMetricsMutex; diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp index 31994e1a92d1..f545bb0738e9 100644 --- a/cmds/statsd/src/StatsService.cpp +++ b/cmds/statsd/src/StatsService.cpp @@ -175,8 +175,13 @@ status_t StatsService::dump(int fd, const Vector<String16>& args) { return NO_MEMORY; // the fd is already open } + bool verbose = false; + if (args.size() > 0 && !args[0].compare(String16("-v"))) { + verbose = true; + } + // TODO: Proto format for incident reports - dump_impl(out); + dump_impl(out, verbose); fclose(out); return NO_ERROR; @@ -185,9 +190,9 @@ status_t StatsService::dump(int fd, const Vector<String16>& args) { /** * Write debugging data about statsd in text format. */ -void StatsService::dump_impl(FILE* out) { - mConfigManager->Dump(out); +void StatsService::dump_impl(FILE* out, bool verbose) { StatsdStats::getInstance().dumpStats(out); + mProcessor->dumpStates(out, verbose); } /** diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h index ba6bd2499820..be20893994f1 100644 --- a/cmds/statsd/src/StatsService.h +++ b/cmds/statsd/src/StatsService.h @@ -140,7 +140,7 @@ private: /** * Text output of dumpsys. */ - void dump_impl(FILE* out); + void dump_impl(FILE* out, bool verbose); /** * Print usage information for the commands diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp index 63bde7d82372..77f54569cb47 100644 --- a/cmds/statsd/src/guardrail/StatsdStats.cpp +++ b/cmds/statsd/src/guardrail/StatsdStats.cpp @@ -45,6 +45,8 @@ const int FIELD_ID_CONFIG_STATS = 3; const int FIELD_ID_ATOM_STATS = 7; const int FIELD_ID_UIDMAP_STATS = 8; const int FIELD_ID_ANOMALY_ALARM_STATS = 9; +const int FIELD_ID_PULLED_ATOM_STATS = 10; +const int FIELD_ID_LOGGER_ERROR_STATS = 11; const int FIELD_ID_MATCHER_STATS_NAME = 1; const int FIELD_ID_MATCHER_STATS_COUNT = 2; @@ -60,6 +62,9 @@ const int FIELD_ID_ATOM_STATS_COUNT = 2; const int FIELD_ID_ANOMALY_ALARMS_REGISTERED = 1; +const int FIELD_ID_LOGGER_STATS_TIME = 1; +const int FIELD_ID_LOGGER_STATS_ERROR_CODE = 2; + std::map<int, long> StatsdStats::kPullerCooldownMap = { {android::util::KERNEL_WAKELOCK, 1}, {android::util::WIFI_BYTES_TRANSFER, 1}, @@ -282,6 +287,15 @@ void StatsdStats::noteAtomLogged(int atomId, int32_t timeSec) { mPushedAtomStats[atomId]++; } +void StatsdStats::noteLoggerError(int error) { + lock_guard<std::mutex> lock(mLock); + // grows strictly one at a time. so it won't > kMaxLoggerErrors + if (mLoggerErrors.size() == kMaxLoggerErrors) { + mLoggerErrors.pop_front(); + } + mLoggerErrors.push_back(std::make_pair(time(nullptr), error)); +} + void StatsdStats::reset() { lock_guard<std::mutex> lock(mLock); resetInternalLocked(); @@ -297,6 +311,7 @@ void StatsdStats::resetInternalLocked() { mAlertStats.clear(); mAnomalyAlarmRegisteredStats = 0; mMatcherStats.clear(); + mLoggerErrors.clear(); for (auto& config : mConfigStats) { config.second.clear_broadcast_sent_time_sec(); config.second.clear_data_drop_time_sec(); @@ -465,6 +480,14 @@ void StatsdStats::dumpStats(FILE* out) const { "lost=%d\n", mUidMapStats.bytes_used(), mUidMapStats.snapshots(), mUidMapStats.changes(), mUidMapStats.dropped_snapshots(), mUidMapStats.dropped_changes()); + + for (const auto& error : mLoggerErrors) { + time_t error_time = error.first; + struct tm* error_tm = localtime(&error_time); + char buffer[80]; + strftime(buffer, sizeof(buffer), "%Y-%m-%d %I:%M%p\n", error_tm); + fprintf(out, "Logger error %d at %s\n", error.second, buffer); + } } void StatsdStats::dumpStats(std::vector<uint8_t>* output, bool reset) { @@ -526,6 +549,14 @@ void StatsdStats::dumpStats(std::vector<uint8_t>* output, bool reset) { mUidMapStats.SerializeToArray(&buffer[0], numBytes); proto.write(FIELD_TYPE_MESSAGE | FIELD_ID_UIDMAP_STATS, &buffer[0], buffer.size()); + for (const auto& error : mLoggerErrors) { + long long token = proto.start(FIELD_TYPE_MESSAGE | FIELD_ID_LOGGER_ERROR_STATS | + FIELD_COUNT_REPEATED); + proto.write(FIELD_TYPE_INT32 | FIELD_ID_LOGGER_STATS_TIME, error.first); + proto.write(FIELD_TYPE_INT32 | FIELD_ID_LOGGER_STATS_ERROR_CODE, error.second); + proto.end(token); + } + output->clear(); size_t bufferSize = proto.size(); output->resize(bufferSize); diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h index 7cb48ead55d8..1f4bfa62c453 100644 --- a/cmds/statsd/src/guardrail/StatsdStats.h +++ b/cmds/statsd/src/guardrail/StatsdStats.h @@ -49,6 +49,8 @@ public: // The max number of old config stats we keep. const static int kMaxIceBoxSize = 20; + const static int kMaxLoggerErrors = 10; + const static int kMaxTimestampCount = 20; const static int kMaxLogSourceCount = 50; @@ -185,6 +187,11 @@ public: void notePullFromCache(int pullAtomId); /** + * Records statsd met an error while reading from logd. + */ + void noteLoggerError(int error); + + /** * Reset the historical stats. Including all stats in icebox, and the tracked stats about * metrics, matchers, and atoms. The active configs will be kept and StatsdStats will continue * to collect stats after reset() has been called. @@ -246,6 +253,9 @@ private: // Maps PullAtomId to its stats. The size is capped by the puller atom counts. std::map<int, PulledAtomStats> mPulledAtomStats; + // Logd errors. Size capped by kMaxLoggerErrors. + std::list<const std::pair<int, int>> mLoggerErrors; + // Stores the number of times statsd modified the anomaly alarm registered with // StatsCompanionService. int mAnomalyAlarmRegisteredStats = 0; diff --git a/cmds/statsd/src/logd/LogReader.cpp b/cmds/statsd/src/logd/LogReader.cpp index 5d43ef3f88bd..0fe896bb10c3 100644 --- a/cmds/statsd/src/logd/LogReader.cpp +++ b/cmds/statsd/src/logd/LogReader.cpp @@ -16,10 +16,11 @@ #include "logd/LogReader.h" -#include <utils/Errors.h> +#include "guardrail/StatsdStats.h" #include <time.h> #include <unistd.h> +#include <utils/Errors.h> using namespace android; using namespace std; @@ -92,16 +93,15 @@ int LogReader::connect_and_read() { // Read forever if (eventLogger) { - + log_msg msg; while (true) { - log_msg msg; - // Read a message err = android_logger_list_read(loggers, &msg); // err = 0 - no content, unexpected connection drop or EOF. // err = +ive number - size of retrieved data from logger // err = -ive number, OS supplied error _except_ for -EAGAIN if (err <= 0) { + StatsdStats::getInstance().noteLoggerError(err); fprintf(stderr, "logcat read failure: %s\n", strerror(err)); break; } diff --git a/cmds/statsd/src/metrics/CountMetricProducer.h b/cmds/statsd/src/metrics/CountMetricProducer.h index 16fc7ee3c6e9..061b7a36817c 100644 --- a/cmds/statsd/src/metrics/CountMetricProducer.h +++ b/cmds/statsd/src/metrics/CountMetricProducer.h @@ -68,6 +68,8 @@ private: // Internal function to calculate the current used bytes. size_t byteSizeLocked() const override; + void dumpStatesLocked(FILE* out, bool verbose) const override{}; + // Util function to flush the old packet. void flushIfNeededLocked(const uint64_t& newEventTime); diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp index e26fe5649090..bfab9e6e490f 100644 --- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp +++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp @@ -233,6 +233,21 @@ void DurationMetricProducer::flushIfNeededLocked(const uint64_t& eventTime) { mCurrentBucketNum += numBucketsForward; } +void DurationMetricProducer::dumpStatesLocked(FILE* out, bool verbose) const { + if (mCurrentSlicedDuration.size() == 0) { + return; + } + + fprintf(out, "DurationMetric %lld dimension size %lu\n", (long long)mMetricId, + (unsigned long)mCurrentSlicedDuration.size()); + if (verbose) { + for (const auto& slice : mCurrentSlicedDuration) { + fprintf(out, "\t%s\n", slice.first.c_str()); + slice.second->dumpStates(out, verbose); + } + } +} + bool DurationMetricProducer::hitGuardRailLocked(const HashableDimensionKey& newKey) { // the key is not new, we are good. if (mCurrentSlicedDuration.find(newKey) != mCurrentSlicedDuration.end()) { diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.h b/cmds/statsd/src/metrics/DurationMetricProducer.h index e06b9a14563d..d8cab92a2b84 100644 --- a/cmds/statsd/src/metrics/DurationMetricProducer.h +++ b/cmds/statsd/src/metrics/DurationMetricProducer.h @@ -68,6 +68,8 @@ private: // Internal function to calculate the current used bytes. size_t byteSizeLocked() const override; + void dumpStatesLocked(FILE* out, bool verbose) const override; + // Util function to flush the old packet. void flushIfNeededLocked(const uint64_t& eventTime); diff --git a/cmds/statsd/src/metrics/EventMetricProducer.h b/cmds/statsd/src/metrics/EventMetricProducer.h index a57b07d6648e..9da0dd0569d6 100644 --- a/cmds/statsd/src/metrics/EventMetricProducer.h +++ b/cmds/statsd/src/metrics/EventMetricProducer.h @@ -62,6 +62,8 @@ private: // Internal function to calculate the current used bytes. size_t byteSizeLocked() const override; + void dumpStatesLocked(FILE* out, bool verbose) const override{}; + // Maps to a EventMetricDataWrapper. Storing atom events in ProtoOutputStream // is more space efficient than storing LogEvent. std::unique_ptr<android::util::ProtoOutputStream> mProto; diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.h b/cmds/statsd/src/metrics/GaugeMetricProducer.h index f267e987f464..1895edf8f729 100644 --- a/cmds/statsd/src/metrics/GaugeMetricProducer.h +++ b/cmds/statsd/src/metrics/GaugeMetricProducer.h @@ -83,6 +83,8 @@ private: // Internal function to calculate the current used bytes. size_t byteSizeLocked() const override; + void dumpStatesLocked(FILE* out, bool verbose) const override{}; + // Util function to flush the old packet. void flushIfNeededLocked(const uint64_t& eventTime); diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h index 3779c4487d23..6f33073c633c 100644 --- a/cmds/statsd/src/metrics/MetricProducer.h +++ b/cmds/statsd/src/metrics/MetricProducer.h @@ -96,6 +96,11 @@ public: return onDumpReportLocked(dumpTimeNs, report); } + void dumpStates(FILE* out, bool verbose) const { + std::lock_guard<std::mutex> lock(mMutex); + dumpStatesLocked(out, verbose); + } + // Returns the memory in bytes currently used to store this metric's data. Does not change // state. size_t byteSize() const { @@ -128,6 +133,7 @@ protected: android::util::ProtoOutputStream* protoOutput) = 0; virtual void onDumpReportLocked(const uint64_t dumpTimeNs, StatsLogReport* report) = 0; virtual size_t byteSizeLocked() const = 0; + virtual void dumpStatesLocked(FILE* out, bool verbose) const = 0; const int64_t mMetricId; diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp index f92951703030..d0737de8acf3 100644 --- a/cmds/statsd/src/metrics/MetricsManager.cpp +++ b/cmds/statsd/src/metrics/MetricsManager.cpp @@ -154,6 +154,20 @@ void MetricsManager::onDumpReport(const uint64_t& dumpTimeStampNs, ConfigMetrics } } +void MetricsManager::dumpStates(FILE* out, bool verbose) { + fprintf(out, "ConfigKey %s, allowed source:", mConfigKey.ToString().c_str()); + { + std::lock_guard<std::mutex> lock(mAllowedLogSourcesMutex); + for (const auto& source : mAllowedLogSources) { + fprintf(out, "%d ", source); + } + } + fprintf(out, "\n"); + for (const auto& producer : mAllMetricProducers) { + producer->dumpStates(out, verbose); + } +} + void MetricsManager::onDumpReport(ProtoOutputStream* protoOutput) { VLOG("=========================Metric Reports Start=========================="); uint64_t dumpTimeStampNs = time(nullptr) * NS_PER_SEC; diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h index a0239fcd1127..9cdbafc75fb1 100644 --- a/cmds/statsd/src/metrics/MetricsManager.h +++ b/cmds/statsd/src/metrics/MetricsManager.h @@ -61,6 +61,8 @@ public: return !mAllowedPkg.empty(); } + void dumpStates(FILE* out, bool verbose); + // Config source owner can call onDumpReport() to get all the metrics collected. virtual void onDumpReport(android::util::ProtoOutputStream* protoOutput); virtual void onDumpReport(const uint64_t& dumpTimeStampNs, ConfigMetricsReport* report); @@ -68,7 +70,6 @@ public: // Computes the total byte size of all metrics managed by a single config source. // Does not change the state. virtual size_t byteSize(); - private: const ConfigKey mConfigKey; diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h index 3e7032d8cf2d..9f750cf419b5 100644 --- a/cmds/statsd/src/metrics/ValueMetricProducer.h +++ b/cmds/statsd/src/metrics/ValueMetricProducer.h @@ -67,6 +67,8 @@ private: // Internal function to calculate the current used bytes. size_t byteSizeLocked() const override; + void dumpStatesLocked(FILE* out, bool verbose) const override{}; + // Util function to flush the old packet. void flushIfNeededLocked(const uint64_t& eventTime); diff --git a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h index 371460e804bd..c2d2cea2a1ff 100644 --- a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h +++ b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h @@ -97,6 +97,8 @@ public: // Predict the anomaly timestamp given the current status. virtual int64_t predictAnomalyTimestampNs(const DurationAnomalyTracker& anomalyTracker, const uint64_t currentTimestamp) const = 0; + // Dump internal states for debugging + virtual void dumpStates(FILE* out, bool verbose) const = 0; protected: // Starts the anomaly alarm. diff --git a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp index 0c99391d491f..412a0c935766 100644 --- a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp +++ b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp @@ -291,6 +291,11 @@ int64_t MaxDurationTracker::predictAnomalyTimestampNs(const DurationAnomalyTrack return currentTimestamp; } +void MaxDurationTracker::dumpStates(FILE* out, bool verbose) const { + fprintf(out, "\t\t sub-durations %lu\n", (unsigned long)mInfos.size()); + fprintf(out, "\t\t current duration %lld\n", (long long)mDuration); +} + } // namespace statsd } // namespace os } // namespace android diff --git a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h index 5d3c15804638..e988ebc06307 100644 --- a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h +++ b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h @@ -48,6 +48,7 @@ public: int64_t predictAnomalyTimestampNs(const DurationAnomalyTracker& anomalyTracker, const uint64_t currentTimestamp) const override; + void dumpStates(FILE* out, bool verbose) const override; private: std::map<HashableDimensionKey, DurationInfo> mInfos; diff --git a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp index 6bf42287e6dd..75d7c0898d78 100644 --- a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp +++ b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp @@ -314,6 +314,12 @@ int64_t OringDurationTracker::predictAnomalyTimestampNs( return eventTimestampNs + thresholdNs; } +void OringDurationTracker::dumpStates(FILE* out, bool verbose) const { + fprintf(out, "\t\t started count %lu\n", (unsigned long)mStarted.size()); + fprintf(out, "\t\t paused count %lu\n", (unsigned long)mPaused.size()); + fprintf(out, "\t\t current duration %lld\n", (long long)mDuration); +} + } // namespace statsd } // namespace os } // namespace android diff --git a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h index 638b7ad7af26..1b74ed1addca 100644 --- a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h +++ b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h @@ -48,6 +48,7 @@ public: int64_t predictAnomalyTimestampNs(const DurationAnomalyTracker& anomalyTracker, const uint64_t currentTimestamp) const override; + void dumpStates(FILE* out, bool verbose) const override; private: // We don't need to keep track of individual durations. The information that's needed is: diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto index f73c4a5303cf..a4ccbd42883d 100644 --- a/cmds/statsd/src/stats_log.proto +++ b/cmds/statsd/src/stats_log.proto @@ -262,4 +262,10 @@ message StatsdStatsReport { optional int64 min_pull_interval_sec = 4; } repeated PulledAtomStats pulled_atom_stats = 10; + + message LoggerErrorStats { + optional int32 logger_disconnection_sec = 1; + optional int32 error_code = 2; + } + repeated LoggerErrorStats logger_error_stats = 11; }
\ No newline at end of file |