MTLog 0.6.1

MTLog 0.6.1

测试已测试
Lang语言 Obj-CObjective C
许可证 MIT
发布最后发布2016 年 10 月

Marin Todorov 维护。



MTLog 0.6.1

  • Marin Todorov

MTLog:为开发者提供的 NSLog 替代品!

日志记录是调试的重要部分,我经常对 NSLog 的灵活性不够感到沮丧。因此,我编写了 MTLog —— 这是我需要的灵活日志工具。


将 MTLog 添加到您的项目中

通过以下方式获取它:1) 源文件

  1. 将 MTLog 仓库作为 zip 文件 下载或克隆它
  2. 将 MTLog 子文件夹复制到您 Xcode 项目的文件夹中
  3. 在项目的 .pch 文件中包含 #import "MTLog.h" 以使 MTLog 在所有类中生效

或 2) 通过 CocoaPods

  1. 在您项目的 Podfile 中添加 MTLog pod
pod 'MTLog'
  1. 在终端内进入项目文件夹后,运行
pod install
  1. 在项目的 .pch 文件中包含 #import "MTLog.h" 以使 MTLog 在所有类中生效

如果您想了解更多的 CocoaPods,请参阅 这篇简短教程


使用 MTLog

MTLog 通过为日志消息添加脚本功能来工作。您按照常规使用 NSLog,但可以在日志消息文本中包含特定命令或添加自己的命令,这些命令将被执行。

最好您通过下面的示例进行阅读。

注意!总是确保您已导入 MTLog.h

前缀命令


默认情况下,新的 MTLog 实例会为您的消息提供一个默认的前缀。默认前缀包括当前类的文件名和当前行号(以下为示例输出)

NSLog(@"My log message!");
MyClass.m:20 > My log message!
_prefix:set(…)

如果您需要除默认以外的前缀,可以使用前缀命令来更改它

NSLog(@"_prefix:set($method $line) My log message!");
NSLog(@"My second message.");
myMethod 20 > My log message!
myMethod 21 > My second message!

注意!:_prefix:set(…) 将设置当前日志消息的前缀,以及之后所有记录的日志消息。

前缀变量

除了文本,您还可以在日志的前缀中使用变量,这些变量将被它们的值替换并应用于每个日志消息。以下是可用变量的列表

$file 当前文件的名称
$class 当前类名
$method 当前方法名
$line 当前行号
$counter 从1开始的计数器。每当你在同一文件的同一线路上进行日志记录时,它都会递增。
_prefix:set()

如果不希望对日志消息使用特殊的前缀,只需调用set而不带任何参数

NSLog(@"_prefix:set()");
_prefix:use(…)

如果您只想更改当前日志消息的前缀,请使用 _prefix:use(…)

NSLog(@"My log message!");
NSLog(@"_prefix:use($method $line) My log message!");
NSLog(@"My second message.");
MyClass.m:20 > My log message!
myMethod 21 > My log message!
MyClass.m:22 > My second message!
_prefix:set(default)

如果您更改前缀并想恢复到默认状态,请将“default”常量传递给前缀命令的set方法

NSLog(@"_prefix:set(default)");

过滤器命令


您可以使用过滤器命令临时过滤日志输出,例如,如果您正在调试某个方法,您不想在此方法完成后看到所有其他日志语句的输出。

您可以使用过滤器以几种不同的方式。

_filter:MyClass.m

在此日志语句后向 _filter 传递一个文件名,您将只能看到该文件的输出。

YourClass.m
...
+(void)message
{
  NSLog(@"Your message!");
}

MyClass.m 
...
NSLog(@"_filter:MyClass.m");
NSLog(@"My message");
[YourClass message];
MyClass.m:20 > My message
// "Your message" will be filtered and not show up in the output console
_filter:MyClass.m(10,200)

您可以通过行号过滤输出。向 _filter 传递一个文件名,并以参数提供应生成控制台输出的行号范围。

NSLog(@"_filter:MyClass.m(10,100)");

此命令将只允许第10行到第100行之间的日志语句生成控制台输出。

_filter:myMethod:withString

您也可以将方法签名传递给 _filter 命令 - 然后,它将只允许与此签名匹配的方法的输出。

组合 _filter 命令

您可以堆叠 _filter 命令。例如,您只想看到 init 方法的输出,尽管您的每个类都有一个 init 方法。您可以将按文件名过滤和按方法名过滤的组合起来。

NSLog(@"_filter:MyClass.m");
NSLog(@"_filter:init");

在此之后,只有 MyClass.m 中的 "init" 的 NSLog 语句将生成输出。

_filter:$this

有时您只想看到您代码中的特定行的输出,不会看到更多(例如,如果 NSLog 语句在 for 循环中)。

NSLog(@"begin counting");
for (int i=1;i<=3;i++) {
  NSLog(@"_filter:$this i=%i", i);
  NSLog(@"more loop output");
}
NSLog(@"_filter:$this loop ended");
NSLog(@"last log message");

一旦您使用 _filter:$this,后续的所有日志消息都将被过滤掉。除了也使用 _filter:$this 的那些之外。上述代码的输出是

MyClass.m:20 > begin counting
MyClass.m:22 > i=1
MyClass.m:22 > i=2
MyClass.m:22 > i=3
MyClass.m:25 > loop ended

删除命令


由于 filter 等命令会影响后续的所有日志消息,您需要一种方法来禁用它们。

_remove:<要删除的命令>

使用 "_remove:" 后跟最初使用的确切命令。如果以上面的例子为例,并结合删除代码,代码可能如下所示

NSLog(@"_filter:$this Message 1");
NSLog(@"Message 2");
NSLog(@"_remove:_filter:$this");  //remove: + the command including arguments
NSLog(@"Message 3");
}

由于删除命令会删除过滤器,您将在输出控制台中看到最后一条日志。

MyClass.m:20 > Message 1
MyClass.m:23 > Message 3

一般来说,所有命令在执行后都会影响所有的日志。因此,您需要使用 _remove 来停用它们。

一些命令,如 _prefix:use(…),是一次性命令,因此您不需要对它们使用 _remove。

路由命令


路由命令允许您将控制台中的输出克隆到日志文件中。如果您想要多次运行应用程序并分析日志内容,这将非常方便。

_route:file(log.txt)

该命令在您的应用程序的文档文件夹中创建 "log.txt",并将所有输出(在命令活动期间)保存到此文件。

_route:file(/<完整路径>/log.txt)

如果您提供了一个文件的全路径,则命令将在您指定的位置创建(或覆盖)它。

_route:file(log.txt,append)

如果您将 "append" 常量作为第二个参数传递,则您的应用程序将在每次运行时向文件中添加内容(而不是每次运行时覆盖它)。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  NSLog(@"message one");
  NSLog(@"message two");
  return YES;
}
--- 2013-09-14 08:36:21 +0000 ---- New log entry ----
[application:didFinishLaunchingWithOptions: 19] message one
[application:didFinishLaunchingWithOptions: 20] message two

--- 2013-09-14 08:42:01 +0000 ---- New log entry ----
[application:didFinishLaunchingWithOptions: 19] message one
[application:didFinishLaunchingWithOptions: 20] message two

搜索命令


有时控制台中的输出如此之多,以至于您找不到您真正想看到的某一行。而且很难找到在代码中的哪一行产生了那个输出,并在这里进行断点。搜索命令可以帮助您找到特定的日志消息。

_search:clear(<搜索项>)

此命令在包含搜索项的每一行之前添加20行空行。当搜索项出现时,它有点像“清理”控制台,以便您可以更容易地找到它。

NSLog(@"_search:clear(vacation)");
…
NSLog(@"Yupee!");
NSLog(@"I'm going on vacation!");
MyClass.m:20 > Yupee!

… //19 more empty lines
MyClass.m:22 > I'm going on vacation!
_search:throw(<搜索项>)

每当搜索项出现在日志消息中时,应用程序会抛出异常并捕获它,这样执行就不会中断。如果您为所有异常设置了断点,则 Xcode 将在搜索插件内中断,这样您就可以调试代码到堆栈。

注册命令


现在是最好的命令 - 允许您将新命令注册到 MTLog。有关于可以在调试时真正帮助您的命令的想法吗?加一个!

_register:command(CommandClassName)

您需要子类化 MTLogPlugin 并覆盖以下方法(按照调用顺序)中的某些或全部方法

// to tell MTLog how many arguments you are expecting
// for example return [0,2] - for zero, one or two args
+(NSRange)expectedNumberOfArgumentsForCommand:(NSString*)command;

// the custom plugin init- name contains the command, value is the part after the colon
// args is an array of the arguments (not trimmed of spaces)
-(instancetype)initWithName:(NSString*)name value:(NSString*)value args:(NSArray*)args;

// the method is invoked just before the plugin is added to enabled plugins list
-(void)willEnableForLog:(MTLog*)log;

// text contains the log message, you can alter it in any way and return it
// look up "env" below
-(NSString*)preProcessLogMessage:(NSString*)text env:(NSArray*)env;

// use this method to react to a command after the message is logged
// look up "env" below
-(void)postProcessLogMessage:(NSString*)text env:(NSArray*)env;

"env" 数组包含以下内容

  1. 文件名
  2. 类名
  3. 方法名
  4. 行号
  5. 所有已启用插件的列表
  6. 所有已注册插件的列表

如果您需要,可以更改启用的和注册的插件列表。

实现新的 “smilie” 命令

让我们看看一个新的名为 “smilie” 的命令的代码,这个命令能为每个记录的消息添加一个表情。

PluginSmilie.h

#import "MTLogPlugin.h"
@interface PluginSmilie : MTLogPlugin
@end

PluginSmilie.m

#import "PluginSmilie.h"
@implementation PluginSmilie
+(NSRange)expectedNumberOfArgumentsForCommand:(NSString*)command
{
  if ([command isEqualToString:@"extended"]) {
    return NSMakeRange(1, 1);
  }
  return NSMakeRange(0, 0);
}

-(NSString*)preProcessLogMessage:(NSString *)text env:(NSArray *)env
{
  if ([self.value isEqualToString:@"classic"]) {
    return [NSString stringWithFormat:@"%@ :-)", text];
  }

  if ([self.value isEqualToString:@"extended"]) {
    return [NSString stringWithFormat:@"%@ :%@)", text, self.args.firstObject];
  }

  return text;
}

@end

这是MTLog的一个完整的工作命令。

expectedNumberOfArgumentsForCommand: 中,你设置你期望 "_smilie:extend" 命令有1到1个参数,而 "_smilie:classic" 命令没有参数。

然后在 preProcessLogMessage:env: 中,你将一个表情添加到文本参数中,这将改变正在记录的消息。

让我们看看如何在你的代码中使用这个新的命令。

#import "PluginSmilie.h"
NSLog(@"_register:smilie(PluginSmilie)");
… 
NSLog(@"Message One");
NSLog(@"_smilie:classic Message Two");
NSLog(@"Message Three");

NSLog(@"_remove:_smilie:classic");
NSLog(@"Message Four");

NSLog(@"_smilie:extended(-{)");
NSLog(@"A hipster message");
MyClass.m:20 > Message One
MyClass.m:21 > Message Two :-)
MyClass.m:22 > Message Three :-)
MyClass.m:25 > Message Four
MyClass.m:28 > A hipster message :-{)

杂项

作者:Marin Todorov


许可

此代码根据MIT许可的条款和条件进行分发。


贡献指南

注意:如果你修复了发现的bug或添加了新功能,请还添加一个单元测试,这样我就能在合并之前确切地知道如何重现bug。