精华内容
下载资源
问答
  • 记录logcat全量日志

    千次阅读 2020-07-23 17:42:30
    import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.Environment; import android.text.TextUtils;...import android.util.Log;...import java.io.IOExceptio.
    package com.geely.gic.rpa.sample;
    import android.content.Context;
    import android.content.Intent;
    import android.net.Uri;
    import android.os.Environment;
    import android.text.TextUtils;
    import android.util.Log;
    
    import java.io.File;
    import java.io.IOException;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.Locale;
    
    /**
     * A tool class is used to capture the logcat generated by the app running.
     * <p>The logcat save path: sdcard/Android/data/packageName/files/Documents/logcatSaveDir</p>
     *
     */
    public class LogWatcher {
    
        public static final String TAG = LogWatcher.class.getSimpleName();
    
        private static volatile LogWatcher instance = null;
    
        private static final String LOG_FILE_PREFIX = "logcat_";
        private static final String LOG_FILE_SUFFIX = ".txt";
    
        private static String sLogDirPath;
    
        private Context mContext;
    
        private Process mLogcatProcess;
    
        private File mLogcatFile;
    
        private LogWatcher() {}
    
        public static LogWatcher getInstance() {
            if (instance == null) {
                synchronized (LogWatcher.class) {
                    if (instance == null) {
                        instance = new LogWatcher();
                    }
                }
            }
            return instance;
        }
    
        /**
         * Init the logcat watcher.
         *
         * @param context    Application context.
         * @param logDirName Logcat save dir
         * @return LogcatWatcher instance.
         */
        public LogWatcher init(Context context, String logDirName) {
            if (context == null)
                throw new IllegalArgumentException("LogWatcher: init failed, context can not be null");
    
            if (TextUtils.isEmpty(logDirName))
                throw new IllegalArgumentException("LogWatcher: init failed, logDirName can not be null");
    
            this.mContext = context.getApplicationContext();
            if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
                File documentFileDir = mContext.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS);
                if (documentFileDir != null) {
                    sLogDirPath = documentFileDir.getAbsolutePath() + File.separator + logDirName;
                } else {
                    Log.e(TAG, "LogWatcher: init LogWatcher failed!");
                }
            } else {
                sLogDirPath = mContext.getFilesDir().getAbsolutePath() + File.separator + logDirName;
            }
    
            return this;
        }
    
        /**
         * Start capture the logcat generated by the app.
         */
        public void startWatch() {
            stopWatch();
    
            if (TextUtils.isEmpty(sLogDirPath)) {
                Log.e(TAG, "LogWatcher: can not watch log, the log dir can not be created");
                return;
            }
    
            mLogcatFile = createNewLogFile();
            if (mLogcatFile == null) {
                Log.e(TAG, "LogWatcher: can not create new log file");
                return;
            } else {
                Log.i(TAG, "LogWatcher: log file save path >>> " + mLogcatFile.getAbsolutePath());
            }
    
            // Clear cache log
            try {
                Process process = Runtime.getRuntime().exec("logcat -c");
                process.destroy();
            } catch (IOException e) {
                e.printStackTrace();
            }
    
            //final String LOGCAT_FILTER_CMD = "logcat -v time *:v | grep \"(" + android.os.Process.myPid() + ")\" > " + newLogFile.getAbsolutePath();
            final String LOGCAT_FILTER_CMD = "logcat -v time *:V -f " + mLogcatFile.getAbsolutePath();
    
            try {
                mLogcatProcess = Runtime.getRuntime().exec(LOGCAT_FILTER_CMD);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        /**
         * Stop capture the logcat generated by the app.
         */
        public void stopWatch() {
            if (mLogcatProcess != null) {
                mLogcatProcess.destroy();
                mLogcatProcess = null;
            }
    
            if (mLogcatFile != null) {
                notifySystemToScan(mContext, mLogcatFile);
            }
        }
    
        private File createNewLogFile() {
            File logSaveDir = new File(sLogDirPath, getCurrentDateStr());
            if (!logSaveDir.exists()) {
                boolean mkdirs = logSaveDir.mkdirs();
                if (!mkdirs) {
                    Log.e(TAG, "LogWatcher: create new save dir failed");
                    return null;
                }
            }
    
            String logFileName = LOG_FILE_PREFIX + getCurrentTimeStr() + LOG_FILE_SUFFIX;
            File logFile = new File(logSaveDir, logFileName);
    
            try {
                boolean createRet = logFile.createNewFile();
                if (!createRet) {
                    Log.e(TAG, "LogWatcher: create new log file failed");
                    return null;
                }
            } catch (IOException e) {
                e.printStackTrace();
                return null;
            }
    
            return logFile;
        }
    
        private static String getCurrentTimeStr() {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss", Locale.getDefault());
            return sdf.format(new Date(System.currentTimeMillis()));
        }
    
        private static String getCurrentDateStr() {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
            return sdf.format(new Date(System.currentTimeMillis()));
        }
    
        private static void notifySystemToScan(Context context, File file) {
            if (context == null || file == null) return;
            Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
            Uri uri = Uri.fromFile(file);
            intent.setData(uri);
            context.sendBroadcast(intent);
        }
    
    }
    

     

    展开全文
  • APP功能简单, 界面元素较少, 逻辑简单, 可作为入门级的APP来练习. 这是一个单机的APP, 使用网络的地方, 仅仅是同步数据到iCloud, 在设备间进行共享, 其他不会再使用网络, 可在断网状态下正常使用. ...
  • sleuth+zipkin 调用追踪全量日志方案 spring cloud中的zipkin日志统计是由sleuth客户端和zipkin服务器组成。sleuth收集客端trace,通过mq将trace发送到zipkin服务器。 zipkin 做持久化和查询展示功能...

    spring cloud中的zipkin日志统计是由sleuth客户端和zipkin服务器组成。 sleuth收集客端trace,通过mq将trace发送到zipkin服务器。

    zipkin 做持久化和查询展示功能。常用kafka+zk集群作为mq将信息由客户端发往服务器,elasticsearch用于trace存储。

    存在以下问题:

    1.大量trace发往zipkin很容易崩溃,通常不能做全量记录。

    2.如果zipkin崩溃或者mq出现问题会导致trace丢失。

    解决:

    a.不引入mq依赖,使用日志记录调用信息。

        @Bean
        public Reporter<Span> reporter(){
            return span ->  { logger.info(span.toString()); }; //输出到trace日志文件
        }
    
        @Bean
        public Sampler sleuthTraceSampler() {
            return Sampler.ALWAYS_SAMPLE;
        } //全量记录

     

    b.使用elk日志方案将日志导入到trace专用索引。

    c.zipkin对数据包括收集和查询展示两模块。我正常配置zipkin+es,就ok了。只是没有不使用收集模块。

     

    posted on 2018-12-16 23:52 NullToValue 阅读( ...) 评论( ...) 编辑 收藏

    转载于:https://www.cnblogs.com/nullAndValue/p/10129224.html

    展开全文
  • 全量日志就是app的运行日志打印等等。有时候光凭Crash日志并不能找到并解决问题,如果有Crash时App的日志输出,则会事半功倍。 CocoaLumberjack是OSX和iOS平台优秀的全量日志抓取第三方库。github链接 ASL (Apple ...

    前言

    全量日志就是app的运行日志打印等等。有时候光凭Crash日志并不能找到并解决问题,如果有CrashApp的日志输出,则会事半功倍。

    CocoaLumberjackOSXiOS平台优秀的全量日志抓取第三方库。github链接

    此篇文章更着重于分析其实现以及结构组成。

    日志重定向

    我们通过日志重定向可以进行将控制台的输出日志存储到文件中

    - (void)redirectLogToDocumentFolder
    {
        // 获取沙盒路径
        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
        NSString *documentDirectory = [paths objectAtIndex:0];
        // 获取打印输出文件路径
        NSString *fileName = [NSString stringWithFormat:@"myData.log"];
        NSString *logFilePath = [documentDirectory stringByAppendingPathComponent:fileName];
        // 先删除已经存在的文件
        NSFileManager *defaultManager = [NSFileManager defaultManager];
        [defaultManager removeItemAtPath:logFilePath error:nil];
        // 将NSLog的输出重定向到文件,因为C语言的printf打印是往stdout打印的,这里也把它重定向到文件
        freopen([logFilePath cStringUsingEncoding:NSASCIIStringEncoding],"a+", stdout);
        freopen([logFilePath cStringUsingEncoding:NSASCIIStringEncoding],"a+", stderr);
    }
    

    这样的坏处是,当重定向之后,控制台不再打印日志输出了,虽然我们可以判断xcode是否连接,然后再进行重定向,来解决连接xcode调试的问题。

    但是还是有不足,就是当你的日志输出你只想自己看到,而不想影响控制台的输出时,显然重定向不能做到,我们需要自己的日志输出入口,同时还要能监听到系统的日志输出,而不影响控制台的日志。

    CocoaLumberjack 就可以帮我们实现这个功能。一般来说我们需要创建3个logger,分别是

    • ASL 用于记录系统的日志输出,这个输出xcode有些不会打印出来
    • TTY 控制台会打印的日志输出
    • File 写入文件中,存为log文件,然后上传,便于分析问题。

    Lumberjack组成

    传统的NSLog()函数将它的输出指向两个地方:

    • 苹果系统日志ASL (Apple System Logs)
    • StdErr(如果StdErr是一个TTY),所以日志语句显示在Xcode控制台

    Capture 捕捉

    DDASLLogCaptureCocoaLumberjack中唯一的一个Capture类,用与捕获ASL日志

    Logger 输出

    logger用于输出日志,有

    • DDASLLogger 用于输出到ASL
    • DDOSLoggeriOS 10之后公开的日志输出方式,用于取代ASL,你可以在官方文档 中查看接口
    • DDTTYLogger 该类为终端输出Xcode控制台输出提供一个日志记录器
    • DDFileLogger 用于将日志输出到文件中,我们一般存储日志文件之后进行压缩。

    要实现替换 NSLog() 的功能,您可以简单地添加DDASLLogger和一个DDTTYLogger
    但是,如果您选择使用文件记录器(DDFileLogger)(以获得更快的性能),
    你可以选择只使用一个文件记录器(DDFileLogger)和一个tty记录器(DDTTYLogger)

    message and formatter 消息以及格式化

    DDLogMessage是封装的消息实体
    DDLogFormatter 是对输出的字符串格式化的类别

    你可以对照CocoaLumberjack源码中的Demos进行更好的理解
    在这里插入图片描述
    里面各种场景都很有参考意义。

    ASL 日志系统

    ASL (Apple system logger)是苹果公司自己实现的一套输出日志的接口。

    通过DDASLLogger.m文件,我们了解到captureAslLogs做了捕捉日志输出的功能

    + (void)captureAslLogs {
        @autoreleasepool
        {
            /*
               We use ASL_KEY_MSG_ID to see each message once, but there's no
               obvious way to get the "next" ID. To bootstrap the process, we'll
               search by timestamp until we've seen a message.
             */
    
            struct timeval timeval = {
                .tv_sec = 0
            };
            gettimeofday(&timeval, NULL);
            unsigned long long startTime = (unsigned long long)timeval.tv_sec;
            __block unsigned long long lastSeenID = 0;
    
            /*
               syslogd posts kNotifyASLDBUpdate (com.apple.system.logger.message)
               through the notify API when it saves messages to the ASL database.
               There is some coalescing - currently it is sent at most twice per
               second - but there is no documented guarantee about this. In any
               case, there may be multiple messages per notification.
    
               Notify notifications don't carry any payload, so we need to search
               for the messages.
             */
            int notifyToken = 0;  // Can be used to unregister with notify_cancel().
            notify_register_dispatch(kNotifyASLDBUpdate, &notifyToken, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^(int token)
            {
                // At least one message has been posted; build a search query.
                @autoreleasepool
                {
                    aslmsg query = asl_new(ASL_TYPE_QUERY);
                    char stringValue[64];
    
                    if (lastSeenID > 0) {
                    //格式化一个64位的字符串
                        snprintf(stringValue, sizeof stringValue, "%llu", lastSeenID);
                       //进行查找 - 按 > seenID 查找
                        asl_set_query(query, ASL_KEY_MSG_ID, stringValue, ASL_QUERY_OP_GREATER | ASL_QUERY_OP_NUMERIC);
                    } else {
                    //时间查找
                        snprintf(stringValue, sizeof stringValue, "%llu", startTime);
                        asl_set_query(query, ASL_KEY_TIME, stringValue, ASL_QUERY_OP_GREATER_EQUAL | ASL_QUERY_OP_NUMERIC);
                    }
    
                    [self configureAslQuery:query];
    
                    // Iterate over new messages.
                    aslmsg msg;
                    aslresponse response = asl_search(NULL, query);
                    
                    while ((msg = asl_next(response)))
                    {
                        [self aslMessageReceived:msg];
    
                        // Keep track of which messages we've seen.
                        lastSeenID = (unsigned long long)atoll(asl_get(msg, ASL_KEY_MSG_ID));
                    }
                    asl_release(response);
                    asl_free(query);
    
                    if (_cancel) {
                        notify_cancel(token);
                        return;
                    }
    
                }
            });
        }
    }
    

    • timeval
      timeval表示时间的一个结构体,
    struct timeval {
            long    tv_sec;         /* 秒 */
            long    tv_usec;        /* 毫秒 */
    };
    

    通过gettimeofday(&timeval, NULL);能够获得当前系统时间


    • notify_register_dispatch用于注册进程间的系统通知,kNotifyASLDBUpdate是一个通知,当日志消息被添加到ASL数据库的时候发出的跨进程通知。
    /*
     * ASL notifications
     * Sent by syslogd to advise clients that new log messages have been
     * added to the ASL database.
     */
    #define kNotifyASLDBUpdate "com.apple.system.logger.message"
    

    通过/usr/include/notify_keys.h文件可以查看更多相关通知内容。


    • aslMessageReceived入参是aslmsg类型,aslget将其转为char字符串类型后,再转为NSString
    	NSString *message = @(messageCString);
    	//这里获取秒和毫微秒(十亿分之一秒)
        const char* secondsCString = asl_get( msg, ASL_KEY_TIME );
        const char* nanoCString = asl_get( msg, ASL_KEY_TIME_NSEC );
        NSTimeInterval seconds = secondsCString ? strtod(secondsCString, NULL) : [NSDate timeIntervalSinceReferenceDate] - NSTimeIntervalSince1970;
        double nanoSeconds = nanoCString? strtod(nanoCString, NULL) : 0;
        //1e9 = 1000000000
        NSTimeInterval totalSeconds = seconds + (nanoSeconds / 1e9);
    
        NSDate *timeStamp = [NSDate dateWithTimeIntervalSince1970:totalSeconds];
    	//生成message
        DDLogMessage *logMessage = [[DDLogMessage alloc]initWithMessage:message
                                                                  level:_captureLevel
                                                                   flag:flag
                                                                context:0
                                                                   file:@"DDASLLogCapture"
                                                               function:nil
                                                                   line:0
                                                                    tag:nil
                                                                options:0
                                                              timestamp:timeStamp];
        //记录到文件
        [DDLog log:async message:logMessage];
    

    这里跟踪log:message:方法最终也是通过写入日志到文件句柄方式

    NSFileHandle *handle = [self lt_currentLogFileHandle];
    [handle seekToEndOfFile];
    [handle writeData:data];
    

    了解到其实现之后,我们就可以自己编写简单的ASL日志捕获工具类,或者使用DDASLLogger输出到ASLDDASLLogger能够将DDLogMessage转化为aslmsg进行赋值之后输出到ASL系统。

    TTY 控制台输出

    前面我们说到了日志重定向,目的是将本来写入到控制台的输出,转而写入到文件中。

    NSLog其实就是写入到文件syslog中,既然要往文件中写,那么肯定就有文件的句柄了,C语言中,有3个句柄,也是我们进行重定向时用到的。

      #define stdin __stdinp
      #define stdout __stdoutp
      #define stderr __stderrp
    

    在iOS平台中,有以下3个:

      #define STDIN_FILENO 0 /* standard input file descriptor */
      #define STDOUT_FILENO 1 /* standard output file descriptor */
      #define STDERR_FILENO 2 /* standard error file descriptor */
    

    NSLog 是在向STDERR_FILENO中写入,你可以使用c语言的输出到文件的fprintf来验证一下:

    NSLog(@"ViewController viewDidLoad");
    fprintf (stderr, "%s\n", "ViewController viewDidLoad222");
    

    控制台可见输出为:

    2016-06-15 12:57:17.286 TestNSlog[68073:1441419] ViewController viewDidLoad
    ViewController viewDidLoad222
    

    关于重定向的更多内容你可以查看 这篇博文

    好了,这下说说TTY的实现,要想实现控制台的输出,那么就输出到STDERR_FILENO就行了,源码中也是这样的实现,值得注意的是,控制台的输出可以输出颜色,所以DDTTYLogger实现中包含了很多颜色的处理,你以搭配CLIColor来了解。

    下面是TTYLogger的输出部分:

    // Write the log message to STDERR
    
            if (isFormatted) {
                // The log message has already been formatted.
                int iovec_len = (_automaticallyAppendNewlineForCustomFormatters) ? 5 : 4;
                struct iovec v[iovec_len];
    
                if (colorProfile) {
                    v[0].iov_base = colorProfile->fgCode;
                    v[0].iov_len = colorProfile->fgCodeLen;
    
                    v[1].iov_base = colorProfile->bgCode;
                    v[1].iov_len = colorProfile->bgCodeLen;
    
                    v[iovec_len - 1].iov_base = colorProfile->resetCode;
                    v[iovec_len - 1].iov_len = colorProfile->resetCodeLen;
                } else {
                    v[0].iov_base = "";
                    v[0].iov_len = 0;
    
                    v[1].iov_base = "";
                    v[1].iov_len = 0;
    
                    v[iovec_len - 1].iov_base = "";
                    v[iovec_len - 1].iov_len = 0;
                }
    
                v[2].iov_base = (char *)msg;
                v[2].iov_len = msgLen;
    
                if (iovec_len == 5) {
                    v[3].iov_base = "\n";
                    v[3].iov_len = (msg[msgLen] == '\n') ? 0 : 1;
                }
    
                writev(STDERR_FILENO, v, iovec_len);
            } else {
                // The log message is unformatted, so apply standard NSLog style formatting.
                ...
    		}
    

    os_log 新日志系统

    iOS 10之后的os_log更为简单

    常用接口有:

    • os_log_with_type 将特定日志级别的消息(如default、info、debug、error)发送到日志系统。
    • os_log_debug 向日志系统发送调试级别消息。
    • os_log_info 向日志系统发送信息级消息。
    • os_log_error 向日志系统发送错误级消息。
    • os_log_fault 向日志系统发送默认级别的消息。
    • os_log 向日志系统发送一个默认级别的消息。与os_log_fault一样

    你可以看看 官方文档

    - (void)logMessage:(DDLogMessage *)logMessage {
        // Skip captured log messages
        if ([logMessage->_fileName isEqualToString:@"DDASLLogCapture"]) {
            return;
        }
    
        if (@available(iOS 10.0, macOS 10.12, tvOS 10.0, watchOS 3.0, *)) {
            NSString * message = _logFormatter ? [_logFormatter formatLogMessage:logMessage] : logMessage->_message;
            if (message != nil) {
                const char *msg = [message UTF8String];
                __auto_type logger = [self logger];
                switch (logMessage->_flag) {
                    case DDLogFlagError  :
                        os_log_error(logger, "%{public}s", msg);
                        break;
                    case DDLogFlagWarning:
                    case DDLogFlagInfo   :
                        os_log_info(logger, "%{public}s", msg);
                        break;
                    case DDLogFlagDebug  :
                    case DDLogFlagVerbose:
                    default              :
                        os_log_debug(logger, "%{public}s", msg);
                        break;
                }
            }
        }
    }
    

    file logger 文件输出

    文件loggerCocoaLumberjack算是比较重要的部分了,其实现全部在DDFileLogger

    DDLogFileManager 文件输出协议

    对于文件管理协议DDLogFileManager,主要是下面的4个属性

    • maximumNumberOfLogFiles 要保存在磁盘上的归档日志文件的最大数量。如果这个属性设置为3,将只保留3个归档日志文件(加上当前活动的日志文件)在磁盘上,你可以设置0将其禁用

    • logFilesDiskQuota 日志占用的最大空间。在滚动日志文件时,所有超过logFilesDiskQuota的旧日志文件都将被删除。你可以设置0将其禁用

    • logsDirectory
      所有日志文件都放在logsDirectory中。
      如果没有指定特定的logsDirectory,则使用默认目录。

    1. Mac上,这是在~/Library/Logs/<Application Name>

    2. iPhone上,这是在 ~/Library/Caches/Logs.

      日志文件被命名为<bundle identifier> <date> <time>.log,例如 Example: com.organization.myapp 2013-12-03 17-14.log

      存档的日志文件会根据“maximumNumberOfLogFiles”属性自动删除。

    • maximumFileSize 允许日志文件增长的最大大小(以字节为单位)。 如果日志文件大于这个值, 将会生成一个新的日志文件进行继续写入。

    • rollingFrequency 滚日志文件的频率。 频率以NSTimeInterval的形式给出,它是一个双精度浮点数,指定以秒为单位的间隔。 一旦日志文件变得这么旧,它就会被重新生成。例如10min = 60x10就重新生成一个日志文件

    您可以通过将“maximumFileSize”设置为0来选择性地禁用由于文件大小而导致的滚动。 如果你这样做,滚动是完全基于“rollingFrequency”。

    您可以选择通过将“rollingFrequency”设置为0(或任何非正数)来禁用由于时间而导致的滚动。 如果你这样做了,滚动仅仅是基于“maximumFileSize”。

    如果您同时禁用“maximumFileSize”和“rollingFrequency”,那么日志文件将永远不会被滚动。 这是强烈不鼓励的。

    这些值默认值为

    // maximumFileSize         -> kDDDefaultLogMaxFileSize
    // rollingFrequency        -> kDDDefaultLogRollingFrequency
    // maximumNumberOfLogFiles -> kDDDefaultLogMaxNumLogFiles
    // logFilesDiskQuota       -> kDDDefaultLogFilesDiskQuota
    
    unsigned long long const kDDDefaultLogMaxFileSize      = 1024 * 1024;      // 1 MB
    NSTimeInterval     const kDDDefaultLogRollingFrequency = 60 * 60 * 24;     // 24 Hours
    NSUInteger         const kDDDefaultLogMaxNumLogFiles   = 5;                // 5 Files
    unsigned long long const kDDDefaultLogFilesDiskQuota   = 20 * 1024 * 1024; // 20 MB
    

    文件压缩

    可以参考Demos中的LogFileCompressor,使用zlib压缩成了gz压缩文件。

    具体你可以查看CompressingLogFileManager.m的实现。


    展开全文
  • 使用adb看日志

    千次阅读 2018-09-26 17:45:56
    之前看日志一般使用两种方式: 1:在AndroidStudio上看日志 2:使用adb logcat 命令来重定向到一个文件中,然后在文件中去看 adb logcat -&amp;amp;gt; c:\test\1.log 一般现场排查问题会让产品都会用第二种...

    之前看日志一般使用两种方式:
    1:在AndroidStudio上看日志
    2:使用adb logcat 命令来重定向到一个文件中,然后在文件中去看
    adb logcat -> c:\test\1.log

    一般现场排查问题会让产品都会用第二种方式来打日志,然后发给研发排查问题。

    现在又发现了一种方式来查看日志,在有的场景下更加方便,就是直接在终端上实时显示日志,因为有时在现场不一定电脑上有AndroidStudio等开发工具,临时装一个这个太麻烦,重定向到文件这种方式又没有了实时性,下面的方法就可以弥补这种场景。

    1:在path上配置好adb命令,或者直接在adb软件所在的目录打开终端
    2:用数据流连上手机,保证adb和手机连接成功
    3:使用命令adb logcat
    这样直接就可以在终端上显示手机上的实时日志。

    但是上面的方法,日志太多了,所有的日志都打上了,怎么过滤我们自己应用所在进程的日志呢,我找了好久用包名过滤的方法也没有找到,最后用pid过滤的,用pid过滤就是每次都需要查询我们应用进程的pid,比较麻烦,但是也凑活用吧。

    过滤进程

    1:连上adb以后,adb shell进入到手机的目录中,然后ps | grep 包名命令获取到我们应用的pid号
    2:退出手机的shell,使用命令adb shell logcat | grep 进程号这样就获取到我们本进程的日志
    在这里插入图片描述

    还可以加颜色,使用adb shell logcat | grep --color=auto 进程号
    在这里插入图片描述

    过滤TAG

    使用adb shell logcat -s TAG,这个命令就可以只显示自己设置的TAG

    展开全文
  • 一旦监控到问题,我们就需要记录下来,但是,很多问题的定位仅靠问题发生的那一刹那记录的信息是不够的,我们需要记录app的全量日志来获取更多的信息。 一,使用NSLog获取全量日志,通过CocoaLumberjack第三方库...
  • 华为交换机日志说明华为交换机日志说明华为交换机日志说明华为交换机日志说明华为交换机日志说明华为交换机日志说明华为交换机日志说明华为交换机日志说明华为交换机日志说明华为交换机日志说明
  • 远程获取android日志

    2012-03-15 19:02:50
    远程,获取android日志,通过邮件方式发送到我的邮箱。对于android开发者有用。
  • 消息队列

    千次阅读 多人点赞 2019-09-19 21:42:59
    一个Consumer Group下的多个Consumer以均摊方式消费消息,如果设置为广播方式,那么这个Consumer Group下的每个实例都消费全量数据。 RocketMQ 数据存储结构 如上图所示,RocketMQ采取了一种数据与索引分离的...
  • redis主从之全量复制及增量复制

    千次阅读 2020-06-04 00:15:22
    -1解析出当前为全量复制,回复+FULLRESYNC响应(主机会向从机发送 runid 和 offset,因为 slave 并没有对应的 offset,所以是全量复制) 从节点接收主节点的响应数据保存运行ID和偏移量offset(从机 slave 会保存 主机...
  • 2021【软件测试】面试题合集大放送

    万次阅读 多人点赞 2019-09-10 18:04:37
    网络带宽:一般使用计数器Bytes Total/sec来度量,Bytes Total/sec表示为发送和接收字节的速率,包括帧字符在内。判断网络连接速度是否是瓶颈,可以用该计数器的值和目前网络的带宽比较。 系统指标: 并发用户数:...
  • iOS搭建Log日志系统

    千次阅读 2018-09-26 15:44:47
    CocoaLumberjack是适用于Mac和iOS的快速简单但功能强大且灵活的日志框架。 本文主要介绍基于CocoaLumberjack搭建iOS项目Log日志系统。 CocoaLumberjack开源地址 一、CocoaLumberjack架构 CocoaLumberjack架构 ...
  • docker logs 查看docker容器日志

    千次阅读 2020-02-01 17:53:45
    命令格式 $ docker logs [OPTIONS] CONTAINER Options: --details 显示更多的信息 -f, --follow 跟踪实时日志... --since string 显示自某个timestamp之后的日志,或相对时间,如42m(即42分钟) --tail strin...
  • 增量同步和全量同步是数据库同步的两种方式。 全量同步是一次性同步全部数据,增量同步则只同步两个数据库不同的部分。 多表同步大家肯定都会想用最省事的方法,比如就建立一个公共的Json模板,将读库(reader)和写...
  • Web服务http日志收集

    千次阅读 2019-03-09 20:33:53
    全量查询GET /_search 压力监控(QPS): 可以聚合和报表的类型:   成品案例:     Web服务代码改造: 集成Kafka: pom.xml添加依赖: <groupId>org.springframework....
  • 如何在 Rancher 中统一管理容器日志

    千次阅读 2016-12-05 09:35:05
    原文来源:Rancher Labs... 我们在使用 docker 处理日志的时候多数是采用 docker logs 命令,因为 docker 默认采用的 log-driver 是 json-file,所以 docker 会捕捉每一个容器进程 STDOUTS 和 STDERR,保存在磁盘文件
  • 分布式服务框架

    千次阅读 2016-01-29 10:42:11
    消息可以被保存在队列中,直到被接收者取出,由于消息发送者不需要同步等待消息接收者的响应,消息的异步接收降低了系统集成的耦合度,提升了分布式系统协作的效率,使得系统能够更快地响 应用户,提供更高的吞吐...
  • 全局捕获异常,并输出到日志文件

    千次阅读 2014-09-09 14:57:11
    * 自定义错误处理,收集错误信息,发送错误报告等操作均在此完成 * * @param ex * @return true:如果处理了该异常信息;否则返回 false */ private boolean handleException(Throwable ex) { if (ex =...
  • 实时读取MySQL二进制日志Binlog,并生成 JSON 格式的消息,作为生产者发送给 Kafka,Kinesis、RabbitMQ、Redis、Google Cloud Pub/Sub、文件或其它平台的应用程序。 2,官网地址:...
  • bababa,他一脸不屑,至于这么麻烦吗,搞个时间点,该时刻之前全量,之后读取对应时刻之后的binlog. 首先,自己对binlog有那些列,每个列是什么背诵不出来,只知道有个position的一个binlog位置编号,有没有记录时候的时间...
  • Reader:数据采集模块,负责采集数据源的数据,将数据发送给Framework。 Writer:数据写入模块,负责不断向Framework取数据,并将数据写入到目的端。 Framework:用于连接reader和writer,作为两者的数据传输通道...
  • 淘宝秒杀系统内幕

    千次阅读 2017-02-08 14:14:35
    导读:最初的秒杀系统的原型是淘宝详情上的定时上架功能,由于有些卖家为了吸引眼球,把价格压得很低。但这给的详情系统带来了很大压力,为了将这种突发流量隔离,才设计了秒杀系统,文章主要介绍大秒...经过日志统计,
  • 容器的性能监控和日志管理

    千次阅读 2016-08-16 17:12:07
    另一方面,当前Docker官方支持的日志驱动除了默认的使用本地目录,还可以直接发送到远程的日志存储或日志采集服务,而其中日志采集服务目前仅仅支持Splunk和Fluentd,同样没有Logstash等老一辈开源日志工具的踪影。...
  • 数据源一般是关系型数据库,近几年,随着移动互联网的蓬勃发展,出现了其他类型的数据源,典型的如网站浏览日期、APP浏览日志、IoT设备日志 从技术实现方式来讲,从关系型数据库获取数据,可以细分为全量抽取、增量...
  • 数据源一般是关系型数据库,近几年,随着移动互联网的蓬勃发展,出现了其他类型的数据源,典型的如网站浏览日期、APP浏览日志、IoT设备日志 从技术实现方式来讲,从关系型数据库获取数据,可以细分为全量抽取、增量...
  • 命令来做增量和全量备份,在季度备份检查审计中,发现备份出来的库大部分都不可用,因此最好是用 svn 本身提供的功能来进行备份。  优缺点分析:  第一种  svnadmin dump 是官方推荐的备份方式,优点是比较灵活,...
  • 在上篇博客【死磕 Redis】— 主从复制(一) 提到,主从节点在数据同步阶段,主节点会根据当前状态的不同执行不同复制操作,包括:全量复制 和 部分复制,这篇博文将详细介绍这两种情况。 全量复制:用于首次复制...
  • Redis 全量复制详解

    千次阅读 2017-11-29 16:01:29
    对于主节点, 当发送完所有的数据后就认为全量复制完成, 打印成功日志: Synchronization with slave127.0.0.1: 6380 succeeded, 但是对于从节点全量复制依然没有完成, 还有后续步骤需要处理。 7) 从节点接收...
  • 这个时候如果没有备份数据库中的数据,造成的影响将是非常严重的,但是我们备份数据不能每天手动的去全量导出,如果放假忘记了或者啥啥啥的,咋整?所以还是要让备份交给服务器去做调度。 这里推荐的备份工具是...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 16,535
精华内容 6,614
关键字:

发送全量日志