├── .gitignore ├── README.md ├── debug_logger中文文档.md ├── image ├── image.png └── image2.png ├── src └── com │ └── hansbug │ ├── arguments │ ├── Arguments.java │ └── exceptions │ │ ├── ArgumentsException.java │ │ ├── InvalidArgumentFullName.java │ │ ├── InvalidArgumentInfo.java │ │ ├── InvalidArgumentShortName.java │ │ └── NoArgumentName.java │ ├── debug │ ├── DebugHelper.java │ └── exceptions │ │ ├── DebugArgumentsException.java │ │ ├── DebugHelperException.java │ │ └── InvalidDebugLevel.java │ ├── log │ └── LogHelper.java │ └── models │ ├── GenericPair.java │ └── HashDefaultMap.java └── test ├── Main.java ├── test_package_A └── TestClassA.java └── test_package_B └── TestThread.java /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea 2 | /out 3 | /META-INF 4 | /src/META-INF 5 | /debug_logger.iml 6 | /debug.log 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # debug_logger 2 | 3 | `debug_logger` is a powerful debug helper based on the debug informations in the standard output. It can easily manage the output of the debug information, which will help us a lot when debugging.[CHINESE DOCUMENTATION HERE](https://github.com/HansBug/debug_logger/blob/master/debug_logger%E4%B8%AD%E6%96%87%E6%96%87%E6%A1%A3.md) 4 | 5 | ## How to start 6 | 7 | ### Initialize 8 | Firstly, we should initialize the config of the `DebugHelper` at the beginning of the entry point, like this: 9 | ```java 10 | import com.hansbug.debug.DebugHelper; 11 | 12 | public abstract class Main { 13 | public static void main(String[] args) { 14 | DebugHelper.setSettingsFromArguments(args); 15 | } 16 | } 17 | ``` 18 | After this, we can use the `DebugHelper`. 19 | 20 | ### Let's debug 21 | The usage of `DebugHelper` in the program is very easy. You can add this into your program anywhere you like to output the debug information. 22 | ```java 23 | DebugHelper.debugPrintln(2, "My debug information"); 24 | ``` 25 | When you use the `--debug 2`(or more than 2) in the command line, this will create a line of output(**in the standard output**). 26 | ``` 27 | [DEBUG-2][xxxx.java:233 TestClass.testMethod] My debug information 28 | ``` 29 | `xxxx.java:233 TestClass.testMethod` represents the position where you put the `debugPrintln`, in this case it means _the 233rd line_ of the `xxxx.java`, in the method `testMethod` of the class `TestClass`. 30 | 31 | When you use the `--debug 1`, there will be nothing output because we the **debug level** of this piece of debug information is `2`, while what we need is only `1`. 32 | 33 | ### Command line configuration 34 | 35 | * **-D \, --debug \** define the debug level. The maximum of the debug level is `5` and the minimum is `1`. 36 | * **--debug_package_name \** define the limit of the package name(full name, just like `com.hansbug.debug`) 37 | * **--debug_file_name \** define the limit of the file name(short file name, just like `Main.java`, `DebugHelper.java`) 38 | * **--debug_class_name \** define the limit of the class name(short class name, **including inner classes**, like `TestClassA`, `TestInnerClassA`(instead of `TestClassA.TestInnerClassA`)) 39 | * **--debug_method_name \** define the limit of the method name(just like `toString`, ``(constructor method)) 40 | * **--debug_include_children** define whether record the log in subroutines that called by the method in the limit above. 41 | * **--debug_show_thread** define whether show the name of threads which execute the `debugPrintln`. 42 | 43 | #### ATTENTION 44 | 45 | * If `--debug`(or `-D`) not detected, debug mode is DISABLED and file logger will not be processed. 46 | * If debug level is invalid, there will be exception thrown out. 47 | * **All the limit above is regular-expression-supported!** 48 | * **Remember to initialize the configurations at the beginning!!!** 49 | 50 | #### Example 51 | You can try to run the `Main.main` in the `test` directory to see and try the example. 52 | 53 | The command line arguments should be added before running the demo. 54 | 55 | In the `Main.main` in the `test` directory, when we run it without any arguments, its output should like this: 56 | ``` 57 | x: 1, y: -1 58 | x: 3, y: 6 59 | [thread_2] 0 60 | [thread_1] 0 61 | [thread_2] 1 62 | [thread_1] 1 63 | [thread_2] 2 64 | [thread_1] 2 65 | [thread_2] 3 66 | [thread_2] 4 67 | [thread_1] 3 68 | [thread_1] 4 69 | [thread_1] 5 70 | [thread_1] 6 71 | [thread_1] 7 72 | [thread_1] 8 73 | ``` 74 | 75 | if the arguments `--debug 1` is added, its standard output will be: 76 | ``` 77 | [DEBUG-1][Main.java:62 Main.testDebugHelper] ksdhjf 78 | x: 1, y: -1 79 | x: 3, y: 6 80 | [DEBUG-1][TestThread.java:18 TestThread.run] [Thread - "thread_1"] start 81 | [DEBUG-1][TestThread.java:18 TestThread.run] [Thread - "thread_2"] start 82 | [thread_2] 0 83 | [thread_1] 0 84 | [thread_2] 1 85 | [thread_1] 1 86 | [thread_2] 2 87 | [thread_1] 2 88 | [thread_2] 3 89 | [thread_2] 4 90 | [thread_1] 3 91 | [DEBUG-1][TestThread.java:31 TestThread.run] [Thread - "thread_2"] end 92 | [thread_1] 4 93 | [thread_1] 5 94 | [thread_1] 6 95 | [thread_1] 7 96 | [thread_1] 8 97 | [DEBUG-1][TestThread.java:31 TestThread.run] [Thread - "thread_1"] end 98 | ``` 99 | 100 | 101 | if the arguments `--debug 5` is added, its standard output will be: 102 | ``` 103 | [DEBUG-1][Main.java:62 Main.testDebugHelper] ksdhjf 104 | [DEBUG-2][TestClassA.java:12 TestInnerClassA.] TestInnerClassA initialize, x: 0, y: 0 105 | [DEBUG-2][TestClassA.java:20 TestClassA.] TestClassA initialize, x: 0, y: 0 106 | [DEBUG-2][TestClassA.java:31 TestClassA.toString] TestClassA getString, x: 1, y: -1 107 | x: 1, y: -1 108 | [DEBUG-2][TestClassA.java:12 TestInnerClassA.] TestInnerClassA initialize, x: 2, y: 7 109 | [DEBUG-2][TestClassA.java:20 TestClassA.] TestClassA initialize, x: 2, y: 7 110 | [DEBUG-2][TestClassA.java:31 TestClassA.toString] TestClassA getString, x: 3, y: 6 111 | x: 3, y: 6 112 | [DEBUG-1][TestThread.java:18 TestThread.run] [Thread - "thread_1"] start 113 | [DEBUG-1][TestThread.java:18 TestThread.run] [Thread - "thread_2"] start 114 | [DEBUG-2][TestThread.java:21 TestThread.run] [Thread - "thread_1"] execute - 0 and wait for 503 ms 115 | [DEBUG-2][TestThread.java:21 TestThread.run] [Thread - "thread_2"] execute - 0 and wait for 367 ms 116 | [thread_2] 0 117 | [thread_1] 0 118 | [DEBUG-3][TestThread.java:26 TestThread.run] [Thread - "thread_2"] came back after 367 ms 119 | [DEBUG-2][TestThread.java:21 TestThread.run] [Thread - "thread_2"] execute - 1 and wait for 367 ms 120 | [thread_2] 1 121 | [DEBUG-3][TestThread.java:26 TestThread.run] [Thread - "thread_1"] came back after 504 ms 122 | [DEBUG-2][TestThread.java:21 TestThread.run] [Thread - "thread_1"] execute - 1 and wait for 503 ms 123 | [thread_1] 1 124 | [DEBUG-3][TestThread.java:26 TestThread.run] [Thread - "thread_2"] came back after 368 ms 125 | [DEBUG-2][TestThread.java:21 TestThread.run] [Thread - "thread_2"] execute - 2 and wait for 367 ms 126 | [thread_2] 2 127 | [DEBUG-3][TestThread.java:26 TestThread.run] [Thread - "thread_1"] came back after 503 ms 128 | [DEBUG-2][TestThread.java:21 TestThread.run] [Thread - "thread_1"] execute - 2 and wait for 503 ms 129 | [thread_1] 2 130 | [DEBUG-3][TestThread.java:26 TestThread.run] [Thread - "thread_2"] came back after 368 ms 131 | [DEBUG-2][TestThread.java:21 TestThread.run] [Thread - "thread_2"] execute - 3 and wait for 367 ms 132 | [thread_2] 3 133 | [DEBUG-3][TestThread.java:26 TestThread.run] [Thread - "thread_2"] came back after 368 ms 134 | [DEBUG-2][TestThread.java:21 TestThread.run] [Thread - "thread_2"] execute - 4 and wait for 367 ms 135 | [thread_2] 4 136 | [DEBUG-3][TestThread.java:26 TestThread.run] [Thread - "thread_1"] came back after 503 ms 137 | [DEBUG-2][TestThread.java:21 TestThread.run] [Thread - "thread_1"] execute - 3 and wait for 503 ms 138 | [thread_1] 3 139 | [DEBUG-3][TestThread.java:26 TestThread.run] [Thread - "thread_2"] came back after 368 ms 140 | [DEBUG-1][TestThread.java:31 TestThread.run] [Thread - "thread_2"] end 141 | [DEBUG-3][TestThread.java:26 TestThread.run] [Thread - "thread_1"] came back after 504 ms 142 | [DEBUG-2][TestThread.java:21 TestThread.run] [Thread - "thread_1"] execute - 4 and wait for 503 ms 143 | [thread_1] 4 144 | [DEBUG-3][TestThread.java:26 TestThread.run] [Thread - "thread_1"] came back after 503 ms 145 | [DEBUG-2][TestThread.java:21 TestThread.run] [Thread - "thread_1"] execute - 5 and wait for 503 ms 146 | [thread_1] 5 147 | [DEBUG-3][TestThread.java:26 TestThread.run] [Thread - "thread_1"] came back after 504 ms 148 | [DEBUG-2][TestThread.java:21 TestThread.run] [Thread - "thread_1"] execute - 6 and wait for 503 ms 149 | [thread_1] 6 150 | [DEBUG-3][TestThread.java:26 TestThread.run] [Thread - "thread_1"] came back after 504 ms 151 | [DEBUG-2][TestThread.java:21 TestThread.run] [Thread - "thread_1"] execute - 7 and wait for 503 ms 152 | [thread_1] 7 153 | [DEBUG-3][TestThread.java:26 TestThread.run] [Thread - "thread_1"] came back after 503 ms 154 | [DEBUG-2][TestThread.java:21 TestThread.run] [Thread - "thread_1"] execute - 8 and wait for 503 ms 155 | [thread_1] 8 156 | [DEBUG-3][TestThread.java:26 TestThread.run] [Thread - "thread_1"] came back after 504 ms 157 | [DEBUG-1][TestThread.java:31 TestThread.run] [Thread - "thread_1"] end 158 | ``` 159 | 160 | if the arguments `--debug 5 --debug_package_name "test_package_A"` is added, it will be: 161 | ``` 162 | [DEBUG-2][TestClassA.java:12 TestInnerClassA.] TestInnerClassA initialize, x: 0, y: 0 163 | [DEBUG-2][TestClassA.java:20 TestClassA.] TestClassA initialize, x: 0, y: 0 164 | [DEBUG-2][TestClassA.java:31 TestClassA.toString] TestClassA getString, x: 1, y: -1 165 | x: 1, y: -1 166 | [DEBUG-2][TestClassA.java:12 TestInnerClassA.] TestInnerClassA initialize, x: 2, y: 7 167 | [DEBUG-2][TestClassA.java:20 TestClassA.] TestClassA initialize, x: 2, y: 7 168 | [DEBUG-2][TestClassA.java:31 TestClassA.toString] TestClassA getString, x: 3, y: 6 169 | x: 3, y: 6 170 | [thread_2] 0 171 | [thread_1] 0 172 | [thread_2] 1 173 | [thread_1] 1 174 | [thread_2] 2 175 | [thread_1] 2 176 | [thread_2] 3 177 | [thread_2] 4 178 | [thread_1] 3 179 | [thread_1] 4 180 | [thread_1] 5 181 | [thread_1] 6 182 | [thread_1] 7 183 | [thread_1] 8 184 | ``` 185 | 186 | if the arguments `--debug 5 --debug_package_name "test_package_B" --debug_show_thread` is added, it will be: 187 | ``` 188 | x: 1, y: -1 189 | x: 3, y: 6 190 | [DEBUG-1][Thread-1][TestThread.java:18 TestThread.run] [Thread - "thread_2"] start 191 | [DEBUG-1][Thread-0][TestThread.java:18 TestThread.run] [Thread - "thread_1"] start 192 | [DEBUG-2][Thread-1][TestThread.java:21 TestThread.run] [Thread - "thread_2"] execute - 0 and wait for 367 ms 193 | [DEBUG-2][Thread-0][TestThread.java:21 TestThread.run] [Thread - "thread_1"] execute - 0 and wait for 503 ms 194 | [thread_2] 0 195 | [thread_1] 0 196 | [DEBUG-3][Thread-1][TestThread.java:26 TestThread.run] [Thread - "thread_2"] came back after 368 ms 197 | [DEBUG-2][Thread-1][TestThread.java:21 TestThread.run] [Thread - "thread_2"] execute - 1 and wait for 367 ms 198 | [thread_2] 1 199 | [DEBUG-3][Thread-0][TestThread.java:26 TestThread.run] [Thread - "thread_1"] came back after 503 ms 200 | [DEBUG-2][Thread-0][TestThread.java:21 TestThread.run] [Thread - "thread_1"] execute - 1 and wait for 503 ms 201 | [thread_1] 1 202 | [DEBUG-3][Thread-1][TestThread.java:26 TestThread.run] [Thread - "thread_2"] came back after 368 ms 203 | [DEBUG-2][Thread-1][TestThread.java:21 TestThread.run] [Thread - "thread_2"] execute - 2 and wait for 367 ms 204 | [thread_2] 2 205 | [DEBUG-3][Thread-0][TestThread.java:26 TestThread.run] [Thread - "thread_1"] came back after 504 ms 206 | [DEBUG-2][Thread-0][TestThread.java:21 TestThread.run] [Thread - "thread_1"] execute - 2 and wait for 503 ms 207 | [thread_1] 2 208 | [DEBUG-3][Thread-1][TestThread.java:26 TestThread.run] [Thread - "thread_2"] came back after 367 ms 209 | [DEBUG-2][Thread-1][TestThread.java:21 TestThread.run] [Thread - "thread_2"] execute - 3 and wait for 367 ms 210 | [thread_2] 3 211 | [DEBUG-3][Thread-1][TestThread.java:26 TestThread.run] [Thread - "thread_2"] came back after 367 ms 212 | [DEBUG-2][Thread-1][TestThread.java:21 TestThread.run] [Thread - "thread_2"] execute - 4 and wait for 367 ms 213 | [thread_2] 4 214 | [DEBUG-3][Thread-0][TestThread.java:26 TestThread.run] [Thread - "thread_1"] came back after 504 ms 215 | [DEBUG-2][Thread-0][TestThread.java:21 TestThread.run] [Thread - "thread_1"] execute - 3 and wait for 503 ms 216 | [thread_1] 3 217 | [DEBUG-3][Thread-1][TestThread.java:26 TestThread.run] [Thread - "thread_2"] came back after 368 ms 218 | [DEBUG-1][Thread-1][TestThread.java:31 TestThread.run] [Thread - "thread_2"] end 219 | [DEBUG-3][Thread-0][TestThread.java:26 TestThread.run] [Thread - "thread_1"] came back after 504 ms 220 | [DEBUG-2][Thread-0][TestThread.java:21 TestThread.run] [Thread - "thread_1"] execute - 4 and wait for 503 ms 221 | [thread_1] 4 222 | [DEBUG-3][Thread-0][TestThread.java:26 TestThread.run] [Thread - "thread_1"] came back after 503 ms 223 | [DEBUG-2][Thread-0][TestThread.java:21 TestThread.run] [Thread - "thread_1"] execute - 5 and wait for 503 ms 224 | [thread_1] 5 225 | [DEBUG-3][Thread-0][TestThread.java:26 TestThread.run] [Thread - "thread_1"] came back after 504 ms 226 | [DEBUG-2][Thread-0][TestThread.java:21 TestThread.run] [Thread - "thread_1"] execute - 6 and wait for 503 ms 227 | [thread_1] 6 228 | [DEBUG-3][Thread-0][TestThread.java:26 TestThread.run] [Thread - "thread_1"] came back after 503 ms 229 | [DEBUG-2][Thread-0][TestThread.java:21 TestThread.run] [Thread - "thread_1"] execute - 7 and wait for 503 ms 230 | [thread_1] 7 231 | [DEBUG-3][Thread-0][TestThread.java:26 TestThread.run] [Thread - "thread_1"] came back after 503 ms 232 | [DEBUG-2][Thread-0][TestThread.java:21 TestThread.run] [Thread - "thread_1"] execute - 8 and wait for 503 ms 233 | [thread_1] 8 234 | [DEBUG-3][Thread-0][TestThread.java:26 TestThread.run] [Thread - "thread_1"] came back after 505 ms 235 | [DEBUG-1][Thread-0][TestThread.java:31 TestThread.run] [Thread - "thread_1"] end 236 | ``` 237 | 238 | ## Javadoc 239 | (not yet created :-( ) 240 | -------------------------------------------------------------------------------- /debug_logger中文文档.md: -------------------------------------------------------------------------------- 1 | ## debug_logger使用指南 2 | 3 | >debug_logger是Hansbug开发的一款通过输出调试信息来帮助开发者进行调试并进行日志记录的调试工具。该调试工具基于Java语言,通过标准输出显示帮助信息并保存信息日志以方便开发者查阅。 4 | 5 | ### How to start 6 | 7 | #### 初始化 8 | 9 | 要在java程序中使用这款调试工具,我们需要导入 **debug_logger.jar**包并在入口方法中调用该包中的 `setSettingsFromArguments(args)`方法,一个典型的案例如下: 10 | ``` 11 | import com.hansbug.debug.DebugHelper; 12 | 13 | public abstract class Main { 14 | public static void main(String[] args) { 15 | DebugHelper.setSettingsFromArguments(args); 16 | } 17 | } 18 | ``` 19 | 20 | 如此,通过设置运行时的参数,我们可以控制debug_logger 21 | 的行为来帮助我们更好地调试。 22 | 23 | #### 具体的调用和输出样例 24 | 25 | 在代码中使用这款调试工具非常简单,我们只要在希望输出信息的地方加入如下的代码, 像这样: 26 | ```java 27 | DebugHelper.debugPrintln(2, "My debug information"); 28 | ``` 29 | 30 | 或者这样: 31 | 32 | ```java 33 | DebugHelper.debugPrintln(2, String.format( 34 | "[Thread - "%s"] execute - %s and wait for %s ms", 35 | this.thread_name,i,this.timespan)); 36 | ``` 37 | 38 | 而他的输出类似这样: 39 | ``` 40 | [DEBUG - 2][xxxx.java:233 TestClass.testMethod] My debug information 41 | ``` 42 | 43 | 以及这样: 44 | ``` 45 | [DEBUG-2][Thread-0][TestThread.java:21 TestThread.run] 46 | [Thread - "thread_1"] execute - 0 and wait for 503 ms 47 | ``` 48 | 49 | 其中 `xxx.java:233`表示该调试命令的调用文件和所在行,你可以根据自己的需求定制化这个工具的输出格式。 50 | 51 | #### 调试工具的命令格式 52 | 53 | >需要说明的是,这款工具可以通过命令行使用,因此linux的用户会感到非常熟悉,而如果你选择通过IDE使用,当然也没有任何问题,在文档的最后会以Eclipse为例向您介绍如何在IDE中使用这款调试工具。 54 | 55 | |命令行参数|用途| 56 | |---|---| 57 | |-D / --debug |所有命令的前提,同时level是 **必须**参数,最小为1,最大为5| 58 | |--debug_package_name |只输出参数中目标package中的debug信息,例如`"com.hansbug.debug"`| 59 | |--debug_file_name |只输出参数中目标文件中的debug信息,例如`"DebugHelper.java"`| 60 | |--debug_class_name |只输出参数中目标类中的debug信息,例如`"TestClassA"`,`"TestInnerClassA"`,需要注明的是 *innerclass* 也会被单独识别| 61 | |--debug_method_name |只输出参数中目标方法中的debug信息,例如`"toString"`(如果是构造函数的话,可以直接使用``)| 62 | |--debug_include_children|当使用带`_name`方法时,此命令控制是否输出子方法中的信息| 63 | |--debug_show_thread|控制是否输出当前`debugPrintln`的调用线程| 64 | 65 | #### 注意事项 66 | 67 | + 如果运行时没有`--debug `或者`-D `的话,那么调试和日志模块将不会启动(**默认DISABLED**) 68 | + 务必在进入主函数时 **初始化** 69 | 70 | #### 如何在Eclipse下使用debug_logger命令 71 | 72 | ##### Step1 73 | 在一个项目中使用此调试工具,首先需要引入 **debug_logger.jar**包,一个简单的引入方法是在复制jar包到当前项目下,并右键jar包选择 74 | 75 | build path > add to build path 76 | 77 | ##### Step2 78 | 在需要的输出的地方调用相应的方法,并在运行前在`run configurations`中输入命令。 79 | 一个简单的样例如下图: 80 | 81 | 82 | ![](https://github.com/buaa0110/debug_logger/raw/master/image/image.png) 83 | 84 | ##### Step3 85 | 运行 86 | 87 | 88 | ![](https://github.com/buaa0110/debug_logger/raw/master/image/image2.png) 89 | 90 | --- 91 | 92 | 备注: 93 | 94 | + 更详细的README和源代码请查看[debug_logger][1] 95 | + 更多调试工具的调试技巧请参见[博客][2](博客内容为较早版本,仅供参考) 96 | 97 | [1]:https://github.com/HansBug/debug_logger 98 | [2]:http://www.cnblogs.com/HansBug/p/8701447.html 99 | -------------------------------------------------------------------------------- /image/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HansBug/debug_logger/22b2a0e83853c7273a88df8381bc8b98b4d31639/image/image.png -------------------------------------------------------------------------------- /image/image2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HansBug/debug_logger/22b2a0e83853c7273a88df8381bc8b98b4d31639/image/image2.png -------------------------------------------------------------------------------- /src/com/hansbug/arguments/Arguments.java: -------------------------------------------------------------------------------- 1 | package com.hansbug.arguments; 2 | 3 | import com.hansbug.arguments.exceptions.InvalidArgumentFullName; 4 | import com.hansbug.arguments.exceptions.InvalidArgumentInfo; 5 | import com.hansbug.arguments.exceptions.InvalidArgumentShortName; 6 | import com.hansbug.arguments.exceptions.NoArgumentName; 7 | import com.hansbug.models.HashDefaultMap; 8 | 9 | 10 | /** 11 | * 参数解析器对象 12 | */ 13 | public class Arguments { 14 | /** 15 | * 单项设置项信息 16 | */ 17 | private class ArgumentInfo { 18 | /** 19 | * 短名 20 | */ 21 | private String short_name; 22 | 23 | /** 24 | * 全名 25 | */ 26 | private String full_name; 27 | 28 | /** 29 | * 是否后面跟随值 30 | */ 31 | private boolean value_required; 32 | 33 | /** 34 | * 参数默认值 35 | */ 36 | private String default_value; 37 | 38 | /** 39 | * 基本初始化函数 40 | * 41 | * @param short_name 短名 42 | * @param full_name 长名 43 | * @param value_required 是否有值跟随 44 | * @param default_value 默认值 45 | * @throws InvalidArgumentInfo 非法参数项类 46 | */ 47 | ArgumentInfo(String short_name, String full_name, boolean value_required, String default_value) throws InvalidArgumentInfo { 48 | if ((short_name != null) && (short_name.length() != 1)) { 49 | throw new InvalidArgumentShortName(short_name); 50 | } 51 | if ((full_name != null) && (full_name.length() <= 1)) { 52 | throw new InvalidArgumentFullName(full_name); 53 | } 54 | if ((full_name == null) && (short_name == null)) { 55 | throw new NoArgumentName(); 56 | } 57 | this.short_name = short_name; 58 | this.full_name = full_name; 59 | this.value_required = value_required; 60 | this.default_value = default_value; 61 | } 62 | 63 | /** 64 | * 基本初始化函数(默认值null) 65 | * 66 | * @param short_name 短名 67 | * @param full_name 长名 68 | * @param value_required 是否有值跟随 69 | * @throws InvalidArgumentInfo 非法参数项类 70 | */ 71 | public ArgumentInfo(String short_name, String full_name, boolean value_required) throws InvalidArgumentInfo { 72 | this(short_name, full_name, value_required, null); 73 | } 74 | 75 | /** 76 | * 获取短名 77 | * 78 | * @return 短名 79 | */ 80 | String getShortName() { 81 | return this.short_name; 82 | } 83 | 84 | /** 85 | * 获取长名 86 | * 87 | * @return 长名 88 | */ 89 | String getFullName() { 90 | return this.full_name; 91 | } 92 | 93 | /** 94 | * 获取是否需要值 95 | * 96 | * @return 是否需要值 97 | */ 98 | boolean getValueRequired() { 99 | return this.value_required; 100 | } 101 | 102 | /** 103 | * 参数项默认值 104 | * 105 | * @return 默认值 106 | */ 107 | String getDefaultValue() { 108 | return this.default_value; 109 | } 110 | } 111 | 112 | /** 113 | * 参数哈希类 114 | */ 115 | private HashDefaultMap argument_hash = new HashDefaultMap<>(null); 116 | 117 | /** 118 | * 默认构造函数 119 | */ 120 | public Arguments() { 121 | } 122 | 123 | /** 124 | * 添加参数项 125 | * 126 | * @param short_name 短名 127 | * @param full_name 长名 128 | * @param value_required 是否尾随数值 129 | * @throws InvalidArgumentInfo 非法参数项 130 | */ 131 | public void addArgs(String short_name, String full_name, boolean value_required) throws InvalidArgumentInfo { 132 | addArgs(short_name, full_name, value_required, null); 133 | } 134 | 135 | /** 136 | * 添加参数项 137 | * 138 | * @param short_name 短名 139 | * @param full_name 长名 140 | * @param value_required 是否尾随数值 141 | * @param default_value 默认值 142 | * @throws InvalidArgumentInfo 非法参数项 143 | */ 144 | public void addArgs(String short_name, String full_name, boolean value_required, String default_value) throws InvalidArgumentInfo { 145 | ArgumentInfo ai = new ArgumentInfo(short_name, full_name, value_required, default_value); 146 | if (ai.getShortName() != null) { 147 | argument_hash.put(ai.getShortName(), ai); 148 | } 149 | if (ai.getFullName() != null) { 150 | argument_hash.put(ai.getFullName(), ai); 151 | } 152 | } 153 | 154 | /** 155 | * 解析args数组 156 | * 157 | * @param args args数组 158 | * @return 参数表结果 159 | */ 160 | public HashDefaultMap parseArguments(String[] args) { 161 | HashDefaultMap result = new HashDefaultMap<>(null); // initialize default hash 162 | for (String key : argument_hash.keySet()) { // set the default value 163 | String value = argument_hash.get(key).default_value; 164 | if (value != null) result.put(key, value); 165 | } 166 | 167 | for (int i = 0; i < args.length; i++) { 168 | String present_item = args[i]; 169 | String name; 170 | if ((present_item.length() > 2) && present_item.substring(0, 2).equals("--")) { // full name 171 | name = present_item.substring(2); 172 | } else if ((present_item.length() > 1) && present_item.substring(0, 1).equals("-")) { // short name 173 | name = present_item.substring(1); 174 | } else { 175 | continue; 176 | } 177 | if (argument_hash.get(name) != null) { // argument name exists 178 | ArgumentInfo ai = argument_hash.get(name); 179 | String value; 180 | if (ai.value_required && (i < (args.length - 1))) { 181 | value = args[i + 1]; 182 | } else { 183 | value = ""; 184 | } 185 | if (ai.getShortName() != null) { 186 | result.put(ai.getShortName(), value); 187 | } 188 | if (ai.getFullName() != null) { 189 | result.put(ai.getFullName(), value); 190 | } 191 | } 192 | } 193 | 194 | return result; 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /src/com/hansbug/arguments/exceptions/ArgumentsException.java: -------------------------------------------------------------------------------- 1 | package com.hansbug.arguments.exceptions; 2 | 3 | /** 4 | * Argument异常类 5 | */ 6 | public class ArgumentsException extends Exception { 7 | /** 8 | * Argument异常构造类 9 | * 10 | * @param msg 异常信息 11 | */ 12 | public ArgumentsException(String msg) { 13 | super(msg); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/com/hansbug/arguments/exceptions/InvalidArgumentFullName.java: -------------------------------------------------------------------------------- 1 | package com.hansbug.arguments.exceptions; 2 | 3 | /** 4 | * 非法参数全名异常类 5 | */ 6 | public class InvalidArgumentFullName extends InvalidArgumentInfo { 7 | /** 8 | * 非法参数全名初始化 9 | * 10 | * @param full_name 全名 11 | */ 12 | public InvalidArgumentFullName(String full_name) { 13 | super(String.format("Invalid full name - %s", full_name)); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/com/hansbug/arguments/exceptions/InvalidArgumentInfo.java: -------------------------------------------------------------------------------- 1 | package com.hansbug.arguments.exceptions; 2 | 3 | /** 4 | * 非法参数项设置异常类(抽象类) 5 | */ 6 | public abstract class InvalidArgumentInfo extends ArgumentsException { 7 | /** 8 | * 非法参数想设置异常类初始化 9 | * 10 | * @param msg 初始化字符串信息 11 | */ 12 | InvalidArgumentInfo(String msg) { 13 | super(msg); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/com/hansbug/arguments/exceptions/InvalidArgumentShortName.java: -------------------------------------------------------------------------------- 1 | package com.hansbug.arguments.exceptions; 2 | 3 | /** 4 | * 非法参数短名异常类 5 | */ 6 | public class InvalidArgumentShortName extends InvalidArgumentInfo { 7 | /** 8 | * 非法参数短名异常类 9 | * 10 | * @param short_name 短名 11 | */ 12 | public InvalidArgumentShortName(String short_name) { 13 | super(String.format("Invalid short name - %s", short_name)); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/com/hansbug/arguments/exceptions/NoArgumentName.java: -------------------------------------------------------------------------------- 1 | package com.hansbug.arguments.exceptions; 2 | 3 | /** 4 | * 未设置参数名类 5 | */ 6 | public class NoArgumentName extends InvalidArgumentInfo { 7 | /** 8 | * 默认初始化函数 9 | */ 10 | public NoArgumentName() { 11 | super("No argument name setted!"); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/com/hansbug/debug/DebugHelper.java: -------------------------------------------------------------------------------- 1 | package com.hansbug.debug; 2 | 3 | import com.hansbug.arguments.Arguments; 4 | import com.hansbug.arguments.exceptions.ArgumentsException; 5 | import com.hansbug.arguments.exceptions.InvalidArgumentInfo; 6 | import com.hansbug.debug.exceptions.DebugArgumentsException; 7 | import com.hansbug.debug.exceptions.DebugHelperException; 8 | import com.hansbug.debug.exceptions.InvalidDebugLevel; 9 | import com.hansbug.log.LogHelper; 10 | import com.hansbug.models.HashDefaultMap; 11 | 12 | import java.util.regex.Pattern; 13 | 14 | /** 15 | * debug信息输出帮助类 16 | * 使用说明: 17 | * -D , --debug 设置输出debug信息的最大级别 18 | * --debug_package_name 限定输出debug信息的包名(完整包名,支持正则表达式) 19 | * --debug_file_name 限定输出debug信息的文件名(无路径,支持正则表达式) 20 | * --debug_class_name 限定输出debug信息的类名(不包含包名的类名,支持正则表达式) 21 | * --debug_method_name 限定输出的debug信息的方法名(支持正则表达式) 22 | * --debug_include_children 输出限定范围内的所有子调用的debug信息(不加此命令时仅输出限定范围内当前层的debug信息) 23 | */ 24 | public abstract class DebugHelper { 25 | /** 26 | * value constants 27 | */ 28 | private static final int MIN_DEBUG_LEVEL = 1; 29 | private static final int MAX_DEBUG_LEVEL = 5; 30 | 31 | /** 32 | * argument constants 33 | */ 34 | private static final String ARG_SHORT_DEBUG = "D"; 35 | private static final String ARG_FULL_DEBUG = "debug"; 36 | private static final String ARG_FULL_DEBUG_SHOW_THREAD = "debug_show_thread"; 37 | private static final String ARG_FULL_DEBUG_INCLUDE_CHILDREN = "debug_include_children"; 38 | private static final String ARG_FULL_DEBUG_PACKAGE_NAME = "debug_package_name"; 39 | private static final String ARG_FULL_DEBUG_FILE_NAME = "debug_file_name"; 40 | private static final String ARG_FULL_DEBUG_CLASS_NAME = "debug_class_name"; 41 | private static final String ARG_FULL_DEBUG_METHOD_NAME = "debug_method_name"; 42 | private static final String DEBUG_LOG_FILE = "debug.log"; 43 | 44 | /** 45 | * helper value 46 | */ 47 | private static boolean enable_debug = false; 48 | private static int debug_level = MIN_DEBUG_LEVEL; 49 | private static boolean range_include_children = false; 50 | private static boolean show_thread = false; 51 | private static String package_name_regex = null; 52 | private static String file_name_regex = null; 53 | private static String class_name_regex = null; 54 | private static String method_name_regex = null; 55 | private static LogHelper log_helper = new LogHelper(DEBUG_LOG_FILE); 56 | 57 | /** 58 | * 设置是否启用debug 59 | * 60 | * @param enable_debug 启用debug 61 | */ 62 | private static void setEnableDebug(boolean enable_debug) { 63 | DebugHelper.enable_debug = enable_debug; 64 | } 65 | 66 | /** 67 | * 设置是否显示线程信息 68 | * 69 | * @param show_thread 是否显示线程信息 70 | */ 71 | private static void setShowThread(boolean show_thread) { 72 | DebugHelper.show_thread = show_thread; 73 | } 74 | 75 | /** 76 | * 设置debug level 77 | * 78 | * @param debug_level 新的debug level 79 | * @throws InvalidDebugLevel 非法的debug level抛出异常 80 | */ 81 | private static void setDebugLevel(int debug_level) throws InvalidDebugLevel { 82 | if ((debug_level <= MAX_DEBUG_LEVEL) && (debug_level >= MIN_DEBUG_LEVEL)) { 83 | DebugHelper.debug_level = debug_level; 84 | } else { 85 | throw new InvalidDebugLevel(debug_level); 86 | } 87 | } 88 | 89 | 90 | /** 91 | * 设置debug信息输出范围是否包含子调用 92 | * 93 | * @param include_children 是否包含子调用 94 | */ 95 | private static void setRangeIncludeChildren(boolean include_children) { 96 | range_include_children = include_children; 97 | } 98 | 99 | /** 100 | * 设置包名正则筛选 101 | * 102 | * @param regex 正则表达式 103 | */ 104 | private static void setPackageNameRegex(String regex) { 105 | package_name_regex = regex; 106 | } 107 | 108 | /** 109 | * 设置文件名正则筛选 110 | * 111 | * @param regex 正则表达式 112 | */ 113 | private static void setFileNameRegex(String regex) { 114 | file_name_regex = regex; 115 | } 116 | 117 | /** 118 | * 设置类名正则筛选 119 | * 120 | * @param regex 正则表达式 121 | */ 122 | private static void setClassNameRegex(String regex) { 123 | class_name_regex = regex; 124 | } 125 | 126 | /** 127 | * 设置方法正则筛选 128 | * 129 | * @param regex 正则表达式 130 | */ 131 | private static void setMethodNameRegex(String regex) { 132 | method_name_regex = regex; 133 | } 134 | 135 | 136 | /** 137 | * 为程序命令行添加相关的读取参数 138 | * 139 | * @param arguments 命令行对象 140 | * @return 添加完读取参数的命令行对象 141 | * @throws InvalidArgumentInfo 非法命令行异常 142 | */ 143 | private static Arguments setArguments(Arguments arguments) throws InvalidArgumentInfo { 144 | arguments.addArgs(ARG_SHORT_DEBUG, ARG_FULL_DEBUG, true); 145 | arguments.addArgs(null, ARG_FULL_DEBUG_INCLUDE_CHILDREN, false); 146 | arguments.addArgs(null, ARG_FULL_DEBUG_SHOW_THREAD, false); 147 | arguments.addArgs(null, ARG_FULL_DEBUG_PACKAGE_NAME, true); 148 | arguments.addArgs(null, ARG_FULL_DEBUG_FILE_NAME, true); 149 | arguments.addArgs(null, ARG_FULL_DEBUG_CLASS_NAME, true); 150 | arguments.addArgs(null, ARG_FULL_DEBUG_METHOD_NAME, true); 151 | return arguments; 152 | } 153 | 154 | /** 155 | * 根据程序命令行进行DebugHelper初始化 156 | * 157 | * @param arguments 程序命令行参数解析结果 158 | * @throws InvalidDebugLevel DebugLevel非法 159 | */ 160 | private static void setSettingsFromArguments(HashDefaultMap arguments) throws InvalidDebugLevel { 161 | DebugHelper.setEnableDebug(arguments.containsKey(ARG_FULL_DEBUG)); 162 | if (enable_debug) { 163 | DebugHelper.setDebugLevel(Integer.valueOf(arguments.get(ARG_FULL_DEBUG))); 164 | DebugHelper.setRangeIncludeChildren(arguments.containsKey(ARG_FULL_DEBUG_INCLUDE_CHILDREN)); 165 | DebugHelper.setShowThread(arguments.containsKey(ARG_FULL_DEBUG_SHOW_THREAD)); 166 | DebugHelper.setPackageNameRegex(arguments.get(ARG_FULL_DEBUG_PACKAGE_NAME)); 167 | DebugHelper.setFileNameRegex(arguments.get(ARG_FULL_DEBUG_FILE_NAME)); 168 | DebugHelper.setClassNameRegex(arguments.get(ARG_FULL_DEBUG_CLASS_NAME)); 169 | DebugHelper.setMethodNameRegex(arguments.get(ARG_FULL_DEBUG_METHOD_NAME)); 170 | 171 | logger("=====================================DebugHelper initialized!====================================="); 172 | String settings = String.format("[Configuration]debug_level: %s, include_chilren: %s", debug_level, range_include_children); 173 | if (package_name_regex != null) settings += String.format(", package_name: %s", package_name_regex); 174 | if (file_name_regex != null) settings += String.format(", file_name: %s", file_name_regex); 175 | if (class_name_regex != null) settings += String.format(", class_name: %s", class_name_regex); 176 | if (method_name_regex != null) settings += String.format(", method_name: %s", method_name_regex); 177 | logger(settings); 178 | } 179 | } 180 | 181 | /** 182 | * 打印文件日志 183 | * 184 | * @param log 日志行 185 | */ 186 | private static void logger(String log) { 187 | if (enable_debug) log_helper.logger(log); 188 | } 189 | 190 | /** 191 | * 根据String[] args配置DebugHelper设置 192 | * 193 | * @param args 系统传入的命令行参数 194 | * @throws DebugHelperException DebugHelper异常类 195 | */ 196 | public static void setSettingsFromArguments(String[] args) throws DebugHelperException { 197 | Arguments arguments = new Arguments(); 198 | try { 199 | arguments = setArguments(arguments); 200 | } catch (ArgumentsException e) { 201 | throw new DebugArgumentsException(e); 202 | } 203 | setSettingsFromArguments(arguments.parseArguments(args)); 204 | } 205 | 206 | /** 207 | * 判断debug level是否需要打印 208 | * 209 | * @param debug_level debug level 210 | * @return 是否需要打印 211 | */ 212 | private static boolean isLevelValid(int debug_level) { 213 | return enable_debug && (debug_level <= DebugHelper.debug_level); 214 | } 215 | 216 | /** 217 | * 正则表达式是否不匹配 218 | * 219 | * @param regex 正则表达式字符串(null则一定匹配) 220 | * @param str 待匹配字符串 221 | * @return 是否不匹配 222 | */ 223 | private static boolean regexMismatch(String regex, String str) { 224 | return (regex != null) && (!Pattern.matches(regex, str)); 225 | } 226 | 227 | /** 228 | * 判断栈信息是否合法 229 | * 230 | * @param trace 栈信息 231 | * @return 栈信息是否合法 232 | */ 233 | private static boolean isTraceValid(StackTraceElement trace) { 234 | try { 235 | Class cls = Class.forName(trace.getClassName()); 236 | String package_name = (cls.getPackage() != null) ? cls.getPackage().getName() : ""; 237 | boolean package_name_mismatch = regexMismatch(package_name_regex, package_name); 238 | boolean file_name_mismatch = regexMismatch(file_name_regex, trace.getFileName()); 239 | boolean class_name_mismatch = regexMismatch(class_name_regex, cls.getSimpleName()); 240 | boolean method_name_mismatch = regexMismatch(method_name_regex, trace.getMethodName()); 241 | return !(package_name_mismatch || file_name_mismatch || class_name_mismatch || method_name_mismatch); 242 | } catch (ClassNotFoundException e) { 243 | return false; 244 | } 245 | } 246 | 247 | /** 248 | * 判断栈范围是否合法 249 | * 250 | * @return 栈范围是否合法 251 | */ 252 | private static boolean isStackValid(StackTraceElement[] trace_list) { 253 | for (int i = 1; i < trace_list.length; i++) { 254 | StackTraceElement trace = trace_list[i]; 255 | if (isTraceValid(trace)) return true; 256 | } 257 | return false; 258 | } 259 | 260 | /** 261 | * 判断限制范围是否合法 262 | * 263 | * @return 限制范围是否合法 264 | */ 265 | private static boolean isRangeValid(StackTraceElement[] trace_list, StackTraceElement trace) { 266 | if (range_include_children) 267 | return isStackValid(trace_list); 268 | else 269 | return isTraceValid(trace); 270 | } 271 | 272 | 273 | /** 274 | * debug信息输出 275 | * 276 | * @param debug_level debug level 277 | * @param debug_info debug信息 278 | */ 279 | public static void dPrintln(int debug_level, String debug_info) { 280 | StackTraceElement[] trace_list = new Throwable().getStackTrace(); 281 | StackTraceElement trace = trace_list[1]; 282 | String class_method; 283 | int trace_len = trace_list.length; 284 | try { 285 | Class cls = Class.forName(trace.getClassName()); 286 | class_method = String.format("%s.%s", cls.getSimpleName(), trace.getMethodName()); 287 | } catch (ClassNotFoundException e) { 288 | class_method = trace.getMethodName(); 289 | } 290 | String debug_location = String.format("[%s:DEPTH-%d:%s:%s %s]", trace.getFileName(), trace_len - 1, trace.getClassName(), trace.getLineNumber(), class_method); 291 | String thread_information = String.format("[%s]", Thread.currentThread().getName()); 292 | String debug_level_str = String.format("[DEBUG-%s]", debug_level); 293 | if (isLevelValid(debug_level) && isRangeValid(trace_list, trace)) { 294 | String output = String.join("", new String[]{ 295 | debug_level_str, (show_thread ? thread_information : ""), debug_location, " " + debug_info 296 | }); 297 | System.out.println(output); 298 | logger(String.format("[DEBUG OUTPUT] %s", output)); 299 | } else { 300 | logger(String.format("[DEBUG HIDDEN] Location : %s", debug_location)); 301 | } 302 | } 303 | 304 | /** 305 | * debug信息输出 306 | * 307 | * @param debug_level debug level 308 | * @param debug_info debug信息 309 | * @param print_switch print开关,当不需要输出时可以立即关掉 310 | */ 311 | public static void dPrintln(int debug_number, int print_switch, String debug_info) { 312 | StackTraceElement[] trace_list = new Throwable().getStackTrace(); 313 | StackTraceElement trace = trace_list[1]; 314 | String class_method; 315 | int trace_len = trace_list.length; 316 | try { 317 | Class cls = Class.forName(trace.getClassName()); 318 | class_method = String.format("%s.%s", cls.getSimpleName(), trace.getMethodName()); 319 | } catch (ClassNotFoundException e) { 320 | class_method = trace.getMethodName(); 321 | } 322 | String debug_location = String.format("[%s:DEPTH-%d:%s:%s %s]", trace.getFileName(), trace_len - 1, trace.getClassName(), trace.getLineNumber(), class_method); 323 | String thread_information = String.format("[%s]", Thread.currentThread().getName()); 324 | String debug_level_str = String.format("[DEBUG-%s]", debug_number); 325 | if (isRangeValid(trace_list, trace)) { 326 | String output = String.join("", new String[]{ 327 | debug_level_str, (show_thread ? thread_information : ""), debug_location, " " + debug_info 328 | }); 329 | if (print_switch == 0) { 330 | System.out.println(output); 331 | } 332 | logger(String.format("[DEBUG OUTPUT] %s", output)); 333 | } else { 334 | logger(String.format("[DEBUG HIDDEN] Location : %s", debug_location)); 335 | } 336 | } 337 | } 338 | 339 | -------------------------------------------------------------------------------- /src/com/hansbug/debug/exceptions/DebugArgumentsException.java: -------------------------------------------------------------------------------- 1 | package com.hansbug.debug.exceptions; 2 | 3 | import com.hansbug.arguments.exceptions.ArgumentsException; 4 | 5 | /** 6 | * DebugHelper命令行参数错误 7 | */ 8 | public class DebugArgumentsException extends DebugHelperException { 9 | /** 10 | * 参数错误异常对象 11 | */ 12 | private ArgumentsException arguments_exception; 13 | 14 | /** 15 | * DebugHelper命令行参数错误对象初始化 16 | * 17 | * @param arguments_exception 参数错误异常对象 18 | */ 19 | public DebugArgumentsException(ArgumentsException arguments_exception) { 20 | super(arguments_exception.getMessage()); 21 | this.arguments_exception = arguments_exception; 22 | } 23 | 24 | /** 25 | * 获取错误信息 26 | * 27 | * @return 错误信息 28 | */ 29 | @Override 30 | public String getMessage() { 31 | return this.arguments_exception.getMessage(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/com/hansbug/debug/exceptions/DebugHelperException.java: -------------------------------------------------------------------------------- 1 | package com.hansbug.debug.exceptions; 2 | 3 | /** 4 | * DebugHelper异常类 5 | */ 6 | public abstract class DebugHelperException extends Exception { 7 | /** 8 | * 初始化DebugHelper异常 9 | * 10 | * @param msg 异常信息 11 | */ 12 | public DebugHelperException(String msg) { 13 | super(msg); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/com/hansbug/debug/exceptions/InvalidDebugLevel.java: -------------------------------------------------------------------------------- 1 | package com.hansbug.debug.exceptions; 2 | 3 | /** 4 | * 非法debug level异常类 5 | */ 6 | public class InvalidDebugLevel extends DebugHelperException { 7 | /** 8 | * 初始化非法debug level异常类 9 | * 10 | * @param debug_level 非法的debug level 11 | */ 12 | public InvalidDebugLevel(int debug_level) { 13 | this(String.valueOf(debug_level)); 14 | } 15 | 16 | /** 17 | * 初始化非法debug level异常类 18 | * 19 | * @param debug_level 非法的debug level 20 | */ 21 | public InvalidDebugLevel(String debug_level) { 22 | super(String.format("Invalid debug level - %s", debug_level)); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/com/hansbug/log/LogHelper.java: -------------------------------------------------------------------------------- 1 | package com.hansbug.log; 2 | 3 | import java.io.File; 4 | import java.io.FileWriter; 5 | import java.io.IOException; 6 | import java.text.SimpleDateFormat; 7 | import java.util.ArrayList; 8 | import java.util.Date; 9 | 10 | /** 11 | * 日志管理器 12 | */ 13 | public class LogHelper { 14 | /** 15 | * 日志类型 16 | */ 17 | private enum LogType { 18 | SYSTEM, USER 19 | } 20 | 21 | /** 22 | * 单条日志对象 23 | */ 24 | private class Log { 25 | /** 26 | * 日志类型 27 | */ 28 | private LogType type; 29 | 30 | /** 31 | * 日志信息 32 | */ 33 | private String information; 34 | 35 | /** 36 | * 日志时间戳 37 | */ 38 | private long timestamp; 39 | 40 | /** 41 | * 初始化日志(默认为用户日志) 42 | * 43 | * @param information 日志信息 44 | */ 45 | Log(String information) { 46 | this(LogType.USER, information); 47 | } 48 | 49 | /** 50 | * 自定义类型初始化日志 51 | * 52 | * @param type 日志类型 53 | * @param information 日志信息 54 | */ 55 | Log(LogType type, String information) { 56 | this.type = type; 57 | this.information = information; 58 | this.timestamp = System.currentTimeMillis(); 59 | } 60 | 61 | /** 62 | * 获取时间戳 63 | * 64 | * @return 字符串时间戳 65 | */ 66 | private String getFormatTimestamp() { 67 | Date d = new Date(this.timestamp); 68 | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); 69 | return sdf.format(d); 70 | } 71 | 72 | /** 73 | * 导出为文本 74 | * 75 | * @return 输出文本 76 | */ 77 | @Override 78 | public String toString() { 79 | return String.format("[%s,%s] %s", this.type.toString(), this.getFormatTimestamp(), this.information); 80 | } 81 | } 82 | 83 | /** 84 | * 相关默认值 85 | */ 86 | private static final int DEFAULT_MAX_CACHE_LINES = 0; 87 | private static final int DEFAULT_SYNC_TIMESPAN = 100; 88 | 89 | /** 90 | * 文件名 91 | */ 92 | private String filename; 93 | 94 | /** 95 | * 缓存区域 96 | */ 97 | private ArrayList cache_lines; 98 | 99 | /** 100 | * 缓存区域容量 101 | */ 102 | private int max_cache_lines = DEFAULT_MAX_CACHE_LINES; 103 | 104 | /** 105 | * 最后同步时间戳 106 | */ 107 | private long last_sync; 108 | 109 | /** 110 | * 同步最大时间间隔(毫秒) 111 | */ 112 | private long sync_timespan = DEFAULT_SYNC_TIMESPAN; 113 | 114 | 115 | /** 116 | * 根据文件名初始化对象 117 | * 118 | * @param filename 文件名 119 | */ 120 | public LogHelper(String filename) { 121 | this(filename, DEFAULT_MAX_CACHE_LINES, DEFAULT_SYNC_TIMESPAN); 122 | } 123 | 124 | /** 125 | * 根据文件名,最大缓存行数和最大同步时间间隔初始化对象 126 | * 127 | * @param filename 文件名 128 | * @param max_cache_lines 最大缓存行数 129 | * @param sync_timespan 最大时间间隔 130 | */ 131 | private LogHelper(String filename, int max_cache_lines, int sync_timespan) { 132 | this.filename = new File(filename).getAbsolutePath(); 133 | this.max_cache_lines = max_cache_lines; 134 | this.last_sync = System.currentTimeMillis() - sync_timespan - 1; 135 | this.cache_lines = new ArrayList<>(); 136 | this.sync_timespan = sync_timespan; 137 | } 138 | 139 | /** 140 | * 获取文件名 141 | * 142 | * @return 文件名(绝对路径名) 143 | */ 144 | public String getFilename() { 145 | return this.filename; 146 | } 147 | 148 | /** 149 | * 写日志 150 | * 151 | * @param log 日志字符串 152 | */ 153 | public void logger(String log) { 154 | this.cache_lines.add(new Log(log)); 155 | try { 156 | if (dumpable()) dump(); 157 | } catch (Exception e) { 158 | this.cache_lines.add(new Log(LogType.SYSTEM, String.format("[%s] %s", e.getClass().getName(), e.getMessage()))); 159 | } 160 | } 161 | 162 | /** 163 | * 判断是否应该同步日志 164 | * 165 | * @return 是否应该同步日志 166 | */ 167 | private boolean dumpable() { 168 | return (this.cache_lines.size() > this.max_cache_lines) || (this.sync_timespan + this.last_sync < System.currentTimeMillis()); 169 | } 170 | 171 | /** 172 | * 导出缓存 173 | * 174 | * @throws IOException IO错误 175 | */ 176 | private void dump() throws IOException { 177 | FileWriter fw = null; 178 | IOException exception = null; 179 | try { 180 | fw = new FileWriter(new File(this.filename), true); 181 | this.dumpCache(fw); 182 | } catch (IOException e) { 183 | exception = e; 184 | } finally { 185 | if (fw != null) fw.close(); 186 | this.last_sync = System.currentTimeMillis(); 187 | if (exception != null) throw exception; 188 | } 189 | } 190 | 191 | /** 192 | * 导出缓存行(原子) 193 | * 194 | * @param fw filewriter 195 | * @throws IOException IO错误 196 | */ 197 | private synchronized void dumpCache(FileWriter fw) throws IOException { 198 | while (this.cache_lines.size() > 0) { 199 | Log log = this.cache_lines.get(0); 200 | String line = log.toString(); 201 | fw.write(line + System.getProperty("line.separator")); 202 | this.cache_lines.remove(0); 203 | } 204 | } 205 | } 206 | -------------------------------------------------------------------------------- /src/com/hansbug/models/GenericPair.java: -------------------------------------------------------------------------------- 1 | package com.hansbug.models; 2 | 3 | /** 4 | * 二元对(献给C++ STL大佬们) 5 | * 6 | * @param 第一元类型 7 | * @param 第二元类型 8 | */ 9 | public class GenericPair { 10 | /** 11 | * 第一值 12 | */ 13 | private X first_value; 14 | 15 | /** 16 | * 第二值 17 | */ 18 | private Y second_value; 19 | 20 | /** 21 | * 获取第一值 22 | * 23 | * @return 第一值 24 | */ 25 | public X getFirst() { 26 | return this.first_value; 27 | } 28 | 29 | /** 30 | * 设置第一值 31 | * 32 | * @param first 第一值 33 | */ 34 | public void setFirst(X first) { 35 | this.first_value = first; 36 | } 37 | 38 | /** 39 | * 获取第二值 40 | * 41 | * @return 第二值 42 | */ 43 | public Y getSecond() { 44 | return this.second_value; 45 | } 46 | 47 | /** 48 | * 设置第二值 49 | * 50 | * @param second 第二值 51 | */ 52 | public void setSecond(Y second) { 53 | this.second_value = second; 54 | } 55 | 56 | /** 57 | * 初始化二元对 58 | * 59 | * @param first 第一值 60 | * @param second 第二值 61 | */ 62 | public GenericPair(X first, Y second) { 63 | this.first_value = first; 64 | this.second_value = second; 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/com/hansbug/models/HashDefaultMap.java: -------------------------------------------------------------------------------- 1 | package com.hansbug.models; 2 | 3 | import java.util.HashMap; 4 | 5 | /** 6 | * 带默认值的魔改版HashMap(没办法ruby用惯了) 7 | * 8 | * @param Key类型 9 | * @param Value类型 10 | */ 11 | public class HashDefaultMap extends HashMap { 12 | /** 13 | * 是否启用默认值(不启用时完全等价于HashMap) 14 | */ 15 | private boolean enable_default = true; 16 | 17 | /** 18 | * 默认值 19 | */ 20 | private V default_value = null; 21 | 22 | /** 23 | * 基本构造函数 24 | * 25 | * @param default_value 默认值 26 | * @param enable_default 是否启用默认值 27 | */ 28 | public HashDefaultMap(V default_value, boolean enable_default) { 29 | this.default_value = default_value; 30 | this.enable_default = enable_default; 31 | } 32 | 33 | /** 34 | * 基本构造函数 35 | * 36 | * @param default_value 默认值 37 | */ 38 | public HashDefaultMap(V default_value) { 39 | this(default_value, true); 40 | } 41 | 42 | /** 43 | * 基本构造函数(默认值为null) 44 | */ 45 | public HashDefaultMap() { 46 | this(null); 47 | } 48 | 49 | /** 50 | * 重载的get函数(当enable_default时,若key不存在则取默认值,否则按照HashMap的同等行为) 51 | * 52 | * @param key 需要取的key 53 | * @return 取出来的值 54 | */ 55 | @Override 56 | public V get(Object key) { 57 | if (!super.containsKey(key) && this.enable_default) { 58 | return this.default_value; 59 | } else { 60 | return super.get(key); 61 | } 62 | } 63 | 64 | /** 65 | * 获取是否启用默认值 66 | * 67 | * @return 是否启用默认值 68 | */ 69 | public boolean getEnableDefault() { 70 | return this.enable_default; 71 | } 72 | 73 | /** 74 | * 设置是否启用默认值 75 | * 76 | * @param enable_default 是否启用默认值 77 | */ 78 | public void setEnableDefault(boolean enable_default) { 79 | this.enable_default = enable_default; 80 | } 81 | 82 | /** 83 | * 获取默认值 84 | * 85 | * @return 默认值 86 | */ 87 | public Object getDefaultValue() { 88 | return this.default_value; 89 | } 90 | 91 | /** 92 | * 设置默认值 93 | * 94 | * @param default_value 默认值 95 | */ 96 | public void setDefaultValue(V default_value) { 97 | this.default_value = default_value; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /test/Main.java: -------------------------------------------------------------------------------- 1 | import com.hansbug.arguments.Arguments; 2 | import com.hansbug.arguments.exceptions.ArgumentsException; 3 | import com.hansbug.arguments.exceptions.InvalidArgumentInfo; 4 | import com.hansbug.debug.DebugHelper; 5 | import com.hansbug.debug.exceptions.DebugHelperException; 6 | import test_package_A.TestClassA; 7 | import test_package_B.TestThread; 8 | 9 | import java.io.File; 10 | import java.lang.reflect.Method; 11 | import java.text.DateFormat; 12 | import java.text.FieldPosition; 13 | import java.text.ParsePosition; 14 | import java.text.SimpleDateFormat; 15 | import java.util.Date; 16 | import java.util.Map; 17 | 18 | abstract class Main { 19 | public static void main(String[] args) { 20 | // System.out.println(args[0]); 21 | // for (int i = 0; i < 100; i++) { 22 | // Date d = new Date(System.currentTimeMillis()); 23 | // SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); 24 | // System.out.println(sdf.format(d)); 25 | // try { 26 | // Thread.sleep(100); 27 | // }catch (Exception e) { 28 | // 29 | // } 30 | // } 31 | // System.exit(1); 32 | try { 33 | DebugHelper.setSettingsFromArguments(args); 34 | testDebugHelper(args); 35 | 36 | testThread(args); 37 | } catch (Exception e) { 38 | StackTraceElement trace = e.getStackTrace()[1]; 39 | System.out.println(String.format("[%s : %s] [%s] %s", trace.getFileName(), trace.getLineNumber(), e.getClass().getName(), e.getMessage())); 40 | System.exit(1); 41 | } 42 | 43 | } 44 | 45 | /** 46 | * Arguments 测试 47 | * 48 | * @param args 系统命令行数组 49 | * @throws InvalidArgumentInfo 非法Argument信息 50 | */ 51 | private static void testArguments(String[] args) throws InvalidArgumentInfo { 52 | Arguments a = new Arguments(); 53 | a.addArgs("D", "debug", true, "1"); 54 | a.addArgs(null, "debug_show_location", false); 55 | for (Map.Entry entry : a.parseArguments(args).entrySet()) { 56 | System.out.println(String.format("%s --> %s", entry.getKey(), entry.getValue())); 57 | } 58 | } 59 | 60 | private static void testDebugHelper(String[] args) { 61 | // DebugHelper.setSettingsFromArguments(args); 62 | DebugHelper.debugPrintln(1, "ksdhjf"); 63 | 64 | TestClassA t1 = new TestClassA(); 65 | System.out.println(t1.toString()); 66 | 67 | TestClassA t2 = new TestClassA(2, 7); 68 | System.out.println(t2.toString()); 69 | } 70 | 71 | private static void testThread(String[] args) throws InterruptedException { 72 | TestThread tt1 = new TestThread("thread_1", 9, 503); 73 | TestThread tt2 = new TestThread("thread_2", 5, 367); 74 | tt1.start(); 75 | tt2.start(); 76 | tt2.join(); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /test/test_package_A/TestClassA.java: -------------------------------------------------------------------------------- 1 | package test_package_A; 2 | 3 | import com.hansbug.debug.DebugHelper; 4 | 5 | public class TestClassA { 6 | private int x; 7 | private int y; 8 | 9 | public class TestInnerClassA { 10 | private int x, y; 11 | public TestInnerClassA(int x, int y) { 12 | DebugHelper.debugPrintln(2, String.format("TestInnerClassA initialize, x: %s, y: %s", x, y)); 13 | this.x = x; 14 | this.y = y; 15 | } 16 | } 17 | 18 | public TestClassA(int x, int y) { 19 | new TestInnerClassA(x, y); 20 | DebugHelper.debugPrintln(2, String.format("TestClassA initialize, x: %s, y: %s", x, y)); 21 | this.x = x + 1; 22 | this.y = y - 1; 23 | } 24 | 25 | public TestClassA() { 26 | this(0, 0); 27 | } 28 | 29 | @Override 30 | public String toString() { 31 | DebugHelper.debugPrintln(2, String.format("TestClassA getString, x: %s, y: %s", this.x, this.y)); 32 | return String.format("x: %s, y: %s", this.x, this.y); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /test/test_package_B/TestThread.java: -------------------------------------------------------------------------------- 1 | package test_package_B; 2 | 3 | import com.hansbug.debug.DebugHelper; 4 | 5 | public class TestThread extends Thread { 6 | private String thread_name = null; 7 | private int count = 0; 8 | private int timespan = 1000; 9 | 10 | public TestThread(String thread_name, int count, int timespan) { 11 | this.thread_name = thread_name; 12 | this.count = count; 13 | this.timespan = timespan; 14 | } 15 | 16 | @Override 17 | public void run() { 18 | DebugHelper.debugPrintln(1, String.format("[Thread - \"%s\"] start", this.thread_name)); 19 | try { 20 | for (int i = 0; i < count; i++) { 21 | DebugHelper.debugPrintln(2, String.format("[Thread - \"%s\"] execute - %s and wait for %s ms", this.thread_name, i, this.timespan)); 22 | System.out.println(String.format("[%s] %s", this.thread_name, i)); 23 | long time = System.currentTimeMillis(); 24 | Thread.sleep(this.timespan); 25 | long timedelta = System.currentTimeMillis() - time; 26 | DebugHelper.debugPrintln(3, String.format("[Thread - \"%s\"] came back after %s ms", this.thread_name, timedelta)); 27 | } 28 | } catch (InterruptedException e) { 29 | DebugHelper.debugPrintln(1, String.format("[Thread - \"%s\"] interrupted", this.thread_name)); 30 | } 31 | DebugHelper.debugPrintln(1, String.format("[Thread - \"%s\"] end", this.thread_name)); 32 | } 33 | } 34 | --------------------------------------------------------------------------------