HdmiLogger.java revision 2e8f1b6399089626b4f0249427626ba6e63a62ef
1/*
2 * Copyright (C) 2014 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
17package com.android.server.hdmi;
18
19import android.annotation.Nullable;
20import android.os.SystemClock;
21import android.util.Pair;
22import android.util.Slog;
23
24import java.util.HashMap;
25
26/**
27 * A logger that prevents spammy log. For the same log message, it logs once every 20seconds.
28 * This class is not thread-safe.
29 * <p>
30 * For convenience, use single character prefix for all messages.
31 * Here are common acronyms
32 * <ul>
33 *   <li>[T]: Timout
34 *   <li>[R]: Received message
35 *   <li>[S]: Sent message
36 *   <li>[P]: Device polling result
37 * </ul>
38 */
39final class HdmiLogger {
40    private static final String TAG = "HDMI";
41    // Logging duration for same error message.
42    private static final long ERROR_LOG_DURATTION_MILLIS = 20 * 1000;  // 20s
43
44    private static final boolean DEBUG = false;
45
46    private static final ThreadLocal<HdmiLogger> sLogger = new ThreadLocal<>();
47
48    // Key (String): log message.
49    // Value (Pair(Long, Integer)): a pair of last log time millis and the number of logMessage.
50    // Cache for warning.
51    private final HashMap<String, Pair<Long, Integer>> mWarningTimingCache = new HashMap<>();
52    // Cache for error.
53    private final HashMap<String, Pair<Long, Integer>> mErrorTimingCache = new HashMap<>();
54
55    private HdmiLogger() {
56    }
57
58    static final void warning(String logMessage, Object... objs) {
59        getLogger().warningInternal(toLogString(logMessage, objs));
60    }
61
62    private void warningInternal(String logMessage) {
63        String log = updateLog(mWarningTimingCache, logMessage);
64        if (!log.isEmpty()) {
65            Slog.w(TAG, log);
66        }
67    }
68
69    static final void error(String logMessage, Object... objs) {
70        getLogger().errorInternal(toLogString(logMessage, objs));
71    }
72
73    private void errorInternal(String logMessage) {
74        String log = updateLog(mErrorTimingCache, logMessage);
75        if (!log.isEmpty()) {
76            Slog.e(TAG, log);
77        }
78    }
79
80    static final void debug(String logMessage, Object... objs) {
81        getLogger().debugInternal(toLogString(logMessage, objs));
82    }
83
84    private void debugInternal(String logMessage) {
85        if (!DEBUG) {
86            return;
87        }
88        Slog.d(TAG, logMessage);
89    }
90
91    private static final String toLogString(String logMessage, Object[] objs) {
92        if (objs.length > 0) {
93            return String.format(logMessage, objs);
94        } else {
95            return logMessage;
96        }
97    }
98
99    private static HdmiLogger getLogger() {
100        HdmiLogger logger = sLogger.get();
101        if (logger == null) {
102            logger = new HdmiLogger();
103            sLogger.set(logger);
104        }
105        return logger;
106    }
107
108    private static String updateLog(HashMap<String, Pair<Long, Integer>> cache, String logMessage) {
109        long curTime = SystemClock.uptimeMillis();
110        Pair<Long, Integer> timing = cache.get(logMessage);
111        if (shouldLogNow(timing, curTime)) {
112            String log = buildMessage(logMessage, timing);
113            cache.put(logMessage, new Pair<>(curTime, 1));
114            return log;
115        } else {
116            increaseLogCount(cache, logMessage);
117        }
118        return "";
119    }
120
121    private static String buildMessage(String message, @Nullable Pair<Long, Integer> timing) {
122        return new StringBuilder()
123                .append("[").append(timing == null ? 1 : timing.second).append("]:")
124                .append(message).toString();
125    }
126
127    private static void increaseLogCount(HashMap<String, Pair<Long, Integer>> cache,
128            String message) {
129        Pair<Long, Integer> timing = cache.get(message);
130        if (timing != null) {
131            cache.put(message, new Pair<>(timing.first, timing.second + 1));
132        }
133    }
134
135    private static boolean shouldLogNow(@Nullable Pair<Long, Integer> timing, long curTime) {
136        return timing == null || curTime - timing.first > ERROR_LOG_DURATTION_MILLIS;
137    }
138}
139