- 浏览: 3053159 次
- 性别:
- 来自: 海外
文章分类
- 全部博客 (430)
- Programming Languages (23)
- Compiler (20)
- Virtual Machine (57)
- Garbage Collection (4)
- HotSpot VM (26)
- Mono (2)
- SSCLI Rotor (1)
- Harmony (0)
- DLR (19)
- Ruby (28)
- C# (38)
- F# (3)
- Haskell (0)
- Scheme (1)
- Regular Expression (5)
- Python (4)
- ECMAScript (2)
- JavaScript (18)
- ActionScript (7)
- Squirrel (2)
- C (6)
- C++ (10)
- D (2)
- .NET (13)
- Java (86)
- Scala (1)
- Groovy (3)
- Optimization (6)
- Data Structure and Algorithm (3)
- Books (4)
- WPF (1)
- Game Engines (7)
- 吉里吉里 (12)
- UML (1)
- Reverse Engineering (11)
- NSIS (4)
- Utilities (3)
- Design Patterns (1)
- Visual Studio (9)
- Windows 7 (3)
- x86 Assembler (1)
- Android (2)
- School Assignment / Test (6)
- Anti-virus (1)
- REST (1)
- Profiling (1)
- misc (39)
- NetOA (12)
- rant (6)
- anime (5)
- Links (12)
- CLR (7)
- GC (1)
- OpenJDK (2)
- JVM (4)
- KVM (0)
- Rhino (1)
- LINQ (2)
- JScript (0)
- Nashorn (0)
- Dalvik (1)
- DTrace (0)
- LLVM (0)
- MSIL (0)
最新评论
-
mldxs:
虽然很多还是看不懂,写的很好!
虚拟机随谈(一):解释器,树遍历解释器,基于栈与基于寄存器,大杂烩 -
HanyuKing:
Java的多维数组 -
funnyone:
Java 8的default method与method resolution -
ljs_nogard:
Xamarin workbook - .Net Core 中不 ...
LINQ的恶搞…… -
txm119161336:
allocatestlye1 顺序为 // Fields o ...
最近做的两次Java/JVM分享的概要
有个朋友让我帮忙写个伪log的生成器。他提供了一个源log文件和一个配置文件,要每隔一段时间就向一个指定的路径上的log文件添加一些新生成的log。
要求是:
1、从配置文件读入参数,根据配置来决定时间间隔与输出log的路径;
2、从源log文件得到生成log的材料;
3、随机从源log里挑选几行出来,把它开头的时间信息替换成当前时间;
4、以固定的时间间隔向目标路径添加新生成的log,并要求不在log文件的末尾生成空行。
配置文件类似这样:
RT_Config.inc:
然后源log文件类似这样(截取几行):
其实就是IIS生成的一些log而已。
他还提出了额外的要求:最好在运行程序的机器上不需要额外安装什么runtime,于是排除掉了Java和C#,以及Perl、Ruby等语言;虽然Java可以GCJ到native,Ruby也可以通过rubyscript2exe来生成带有Ruby解释器的独立exe文件,但它们生成出来的exe都太大了,也排除;C和C++都不够方便,我不太想在这种小程序上用。所以最后我选择了用D来写这个小程序。
===========================================================================
于是问题可以分解为几个小问题,主要是:
1、从配置文件读入配置;
2、拼接出新的log:获取当前时间并格式化到合适的格式上,然后与源log拼接起来;
3、按固定的时间间隔重复执行写出log的动作。
---------------------------------------------------------------------------
第一个问题很好办。我的解决办法是把整个配置文件读进来,分解成行,然后对每行做匹配,把配置文件里的key-value对保存到D语言提供的关联数组里。
这样声明了一个char[] => char[]的关联数组。注意到D里char[]就是字符串了。
在对行做匹配时,我用了三个正则表达式:
第一个正则表达式用于匹配行首为"//"的行。如果匹配则忽略掉该行。这其实是偷懒了——我没有去匹配在行尾的行注释,因为如果配置文件里出现引号包围的字符串,而字符串的正常内容含有"//"的话,直接用r"//.*$"会把不应该认为是注释的东西也包含进去……这里需要更多的处理,但是我懒得做了。直接规定用户必须把注释符号写在行首就是。
第二个正则表达式用于匹配配置文件里的段标记。如果匹配则同注释一样,忽略掉该行。
第三个正则表达式用于验证配置文件的行是否符合key=value的形式。如果符合,则将key-value对保存到关联数组里。
源log文件也同样,整个文件读进来,然后分解为行,保存起来。
---------------------------------------------------------------------------
第二个问题在D的标准库Phobos的支持下也很好办。特别是当D的字符串是基于char[],也就是说是一个动态数组,用起来很方便。
先要得到当前的系统时间。std.date包里有足够的函数来解决这问题。用std.date.getUTCtime()获取当前时间后,用XXXFromTime()的几个函数把时间转换为字符串,然后用std.string.format()以指定的格式将它们拼接起来。
得到当前时间的字符串之后,随机从源log里选一行出来,把当前时间与去除掉时间的源log拼起来就行。
---------------------------------------------------------------------------
第三个问题比较讨厌。要按照固定的时间间隔来做些事情的话,Java、C#高级语言和JavaScript等脚本语言都提供了直接能用的timer机制,但C/C++的层次上则没有直接能用的timer,D的Phobos也没有。换言之我们要自己实现定时器。有两种思路:
1、busy wait
2、sleep and wait
busy wait就是例如while(true)然后在里面检查时间间隔是不是大于或等于规定值,满足条件的时候执行动作
sleep and wait是在每次执行完动作之后让自己(一个线程)休眠一定时间,等“醒来”的时候再执行一次动作,再休眠,如此循环。
很明显busy wait是很糟糕的选择——它不停的循环,什么事都不做却占着CPU。但是这种做法在C/C++里却很常见。或许大家都很无奈吧 = =
刚才经过隔壁宿舍的的时候看到了一本叫做《C游戏编程从入门到精通》的书,顺手翻了翻,读到了它(还是说是Andre LaMothe?)提供的控制时间延迟的函数:
噢天哪。居然用上了内存到寄存器的地址映射——也就是说直接从寄存器读了当前的clock tick。这比用系统API更“糟糕”了,不采用。这本书居然是在2000年之后才出的,好神奇啊 =v=
(“糟糕”不是说这代码不好。事实上总是得有这样的代码存在于某处,一般是在库里,像是说操作系统的API会有这样的函数的实现。不过某个寄存器到底映射到的地址对平台的依赖性太大了,我们最好不要自己的*应用程序*里直接用……)
sleep and wait则需要库的支持。在C/C++/D里,没有办法不依赖于平台来做这件事。不过依赖就依赖吧诶,总比busy wait好。在D的官网论坛上有人写了一个还不错的实现:http://www.digitalmars.com/d/archives/digitalmars/D/learn/Implementing_a_timer_using_threads_6170.html
下面的代码里就使用了那帖里的Timer。
===========================================================================
说起来,我没写如何让这程序退出的逻辑……要退出就要强制结束进程了 =v=
另外我没有检查目标log的路径是否存在,如果路径上的目录不存在的话程序也会出错。这个得递归的调用mkdir才好解决,懒得做……
用来编译的环境是DMD D 1.028。
好吧,其它也没什么了,完整的程序如下:
loggen.d
要求是:
1、从配置文件读入参数,根据配置来决定时间间隔与输出log的路径;
2、从源log文件得到生成log的材料;
3、随机从源log里挑选几行出来,把它开头的时间信息替换成当前时间;
4、以固定的时间间隔向目标路径添加新生成的log,并要求不在log文件的末尾生成空行。
配置文件类似这样:
RT_Config.inc:
[system] //log format Format=NCSA //log of the dat FileName=D:\temp\today.log //port Listen_Port=8000 //server IP IP=127.0.0.1 //server port Server_port=9000 //time interval (in SECs) Time_Interval=20
然后源log文件类似这样(截取几行):
2008-03-31 00:00:19 10.11.14.56 - 10.11.1.9 80 GET /acip/shownewsh.asp - 200 Mozilla/4.0+(compatible;+MSIE+6.0;+Windows+NT+5.1;+SV1) 2008-03-31 00:00:20 10.11.14.56 - 10.11.1.9 80 GET /acip/images/Delighting+you+always+(Red)+789x382.gif - 304 Mozilla/4.0+(compatible;+MSIE+6.0;+Windows+NT+5.1;+SV1) 2008-03-31 00:00:47 10.11.10.81 - 10.11.1.9 80 GET /acip/shownewsh.asp - 200 Mozilla/4.0+(compatible;+MSIE+6.0;+Windows+NT+5.0) 2008-03-31 00:01:31 10.11.50.67 - 10.11.1.9 80 GET /acip/shownewsh.asp - 200 Mozilla/4.0+(compatible;+MSIE+6.0;+Windows+NT+5.1;+SV1) 2008-03-31 00:01:36 10.11.46.90 - 10.11.1.9 80 GET /acip/shownewsh.asp - 200 Mozilla/4.0+(compatible;+MSIE+6.0;+Windows+NT+5.1;+SV1) 2008-03-31 00:01:38 10.11.44.64 - 10.11.1.9 80 GET /eis/Report/Executive+Information+System - 404 Mozilla/4.0+(compatible;+MSIE+6.0;+Windows+NT+5.0)
其实就是IIS生成的一些log而已。
他还提出了额外的要求:最好在运行程序的机器上不需要额外安装什么runtime,于是排除掉了Java和C#,以及Perl、Ruby等语言;虽然Java可以GCJ到native,Ruby也可以通过rubyscript2exe来生成带有Ruby解释器的独立exe文件,但它们生成出来的exe都太大了,也排除;C和C++都不够方便,我不太想在这种小程序上用。所以最后我选择了用D来写这个小程序。
===========================================================================
于是问题可以分解为几个小问题,主要是:
1、从配置文件读入配置;
2、拼接出新的log:获取当前时间并格式化到合适的格式上,然后与源log拼接起来;
3、按固定的时间间隔重复执行写出log的动作。
---------------------------------------------------------------------------
第一个问题很好办。我的解决办法是把整个配置文件读进来,分解成行,然后对每行做匹配,把配置文件里的key-value对保存到D语言提供的关联数组里。
char[char[]] config; // 配置参数
这样声明了一个char[] => char[]的关联数组。注意到D里char[]就是字符串了。
在对行做匹配时,我用了三个正则表达式:
RegExp commentPattern = RegExp(r"^//.*"); RegExp sectionPattern = RegExp(r"^\[[^\]]+\]"); RegExp keyValuePattern = RegExp(r"(.+)=(.+)");
第一个正则表达式用于匹配行首为"//"的行。如果匹配则忽略掉该行。这其实是偷懒了——我没有去匹配在行尾的行注释,因为如果配置文件里出现引号包围的字符串,而字符串的正常内容含有"//"的话,直接用r"//.*$"会把不应该认为是注释的东西也包含进去……这里需要更多的处理,但是我懒得做了。直接规定用户必须把注释符号写在行首就是。
第二个正则表达式用于匹配配置文件里的段标记。如果匹配则同注释一样,忽略掉该行。
第三个正则表达式用于验证配置文件的行是否符合key=value的形式。如果符合,则将key-value对保存到关联数组里。
源log文件也同样,整个文件读进来,然后分解为行,保存起来。
char[][] source; // 源log的数据
---------------------------------------------------------------------------
第二个问题在D的标准库Phobos的支持下也很好办。特别是当D的字符串是基于char[],也就是说是一个动态数组,用起来很方便。
先要得到当前的系统时间。std.date包里有足够的函数来解决这问题。用std.date.getUTCtime()获取当前时间后,用XXXFromTime()的几个函数把时间转换为字符串,然后用std.string.format()以指定的格式将它们拼接起来。
得到当前时间的字符串之后,随机从源log里选一行出来,把当前时间与去除掉时间的源log拼起来就行。
---------------------------------------------------------------------------
第三个问题比较讨厌。要按照固定的时间间隔来做些事情的话,Java、C#高级语言和JavaScript等脚本语言都提供了直接能用的timer机制,但C/C++的层次上则没有直接能用的timer,D的Phobos也没有。换言之我们要自己实现定时器。有两种思路:
1、busy wait
2、sleep and wait
busy wait就是例如while(true)然后在里面检查时间间隔是不是大于或等于规定值,满足条件的时候执行动作
sleep and wait是在每次执行完动作之后让自己(一个线程)休眠一定时间,等“醒来”的时候再执行一次动作,再休眠,如此循环。
很明显busy wait是很糟糕的选择——它不停的循环,什么事都不做却占着CPU。但是这种做法在C/C++里却很常见。或许大家都很无奈吧 = =
刚才经过隔壁宿舍的的时候看到了一本叫做《C游戏编程从入门到精通》的书,顺手翻了翻,读到了它(还是说是Andre LaMothe?)提供的控制时间延迟的函数:
void Delay(int clicks) { unsigned int far *clock = (unsigned int far *)0x0000046CL; unsigned int now; now = *clock; while (abs(*clock - now) < clicks) { } }
噢天哪。居然用上了内存到寄存器的地址映射——也就是说直接从寄存器读了当前的clock tick。这比用系统API更“糟糕”了,不采用。这本书居然是在2000年之后才出的,好神奇啊 =v=
(“糟糕”不是说这代码不好。事实上总是得有这样的代码存在于某处,一般是在库里,像是说操作系统的API会有这样的函数的实现。不过某个寄存器到底映射到的地址对平台的依赖性太大了,我们最好不要自己的*应用程序*里直接用……)
sleep and wait则需要库的支持。在C/C++/D里,没有办法不依赖于平台来做这件事。不过依赖就依赖吧诶,总比busy wait好。在D的官网论坛上有人写了一个还不错的实现:http://www.digitalmars.com/d/archives/digitalmars/D/learn/Implementing_a_timer_using_threads_6170.html
下面的代码里就使用了那帖里的Timer。
===========================================================================
说起来,我没写如何让这程序退出的逻辑……要退出就要强制结束进程了 =v=
另外我没有检查目标log的路径是否存在,如果路径上的目录不存在的话程序也会出错。这个得递归的调用mkdir才好解决,懒得做……
用来编译的环境是DMD D 1.028。
好吧,其它也没什么了,完整的程序如下:
loggen.d
import std.conv; import std.date; import std.file; import std.path; // import std.random; // for rand() import std.regexp; import std.stdio; import std.string; import std.c.stdlib; import std.c.time; static const char[] CONFIG_FILENAME = "./RT_Config.inc"; static const char[] LOG_SOURCE_FILENAME = "./record.log"; static const int FOREVER = -1; char[][char[]] config; // configuration data int timeInterval; // time interval char[] logFileName; // destination log file's name char[][] source; // source log contents // Load the configuration data, // and set time interval/destination filename bool loadConfig() { char[] file = cast(char[])read(CONFIG_FILENAME); if(file == null) return false; char[][] lines = splitlines(file); RegExp commentPattern = RegExp(r"^//.*"); RegExp sectionPattern = RegExp(r"^\[[^\]]+\]"); RegExp keyValuePattern = RegExp(r"(.+)=(.+)"); foreach (char[] line; lines) { if (commentPattern.test(line)) continue; // skip comments if (sectionPattern.test(line)) continue; // skip section tags if (keyValuePattern.test(line)) { config[toupper(keyValuePattern.match(1))] = keyValuePattern.match(2); } } timeInterval = toInt(config["TIME_INTERVAL"]); logFileName = config["FILENAME"]; return true; } // Load the source log contents bool loadSource() { char[] file = cast(char[])read(LOG_SOURCE_FILENAME); if(file == null) return false; source = splitlines(file); return true; } // get a random number in the range [min, max) // min and max should be a positive integer int random(int min, int max) { int rand = std.c.stdlib.random(20); while (rand < 5) rand = std.c.stdlib.random(20); return rand; } // get a string representation of the current system time // in the format "YYYY-MM-DD hh:mm:ss" char[] getCurrentTimeString() { d_time lNow = std.date.getUTCtime(); return std.string.format("%04d-%02d-%02d " ~ std.date.toTimeString(lNow)[0..$-9], YearFromTime(lNow), MonthFromTime(lNow), DateFromTime(lNow)); } // generate a line of dummy log char[] getLogLine() { int rand = std.c.stdlib.random(source.length); return getCurrentTimeString() ~ source[rand][19..$]; } // exit the program abnormally void abort(char[] message) { writefln("Error: " ~ message); exit(1); } /* // execute an action repeatly with specified time interval // busy wait version void repeat(void delegate() action, int interval, int limit) { if (action == null) return; if (interval < 0) return; time_t old = time(null); while (limit != 0) { time_t now = time(null); if (now >= old + interval) { old = now; action(); --limit; } } } */ // execute an action repeatly with specified time interval // sleep-and-wait version // TODO: fix the limit param... void repeat(void delegate() action, int interval, int limit) { Timer timer = new Timer(interval, action, (limit < 0)); timer.start(); timer.wait(); } // program entry point void main(char[][] args) { // load configuration if (!loadConfig()) abort("invalid configuration file."); // load source log if (!loadSource()) abort("invalid source log file."); // append a few lines of log first int r = random(5, 20); // append generated log to destination for (int i = 0; i < r; ++i) { if (exists(logFileName) && isfile(logFileName)) { append(logFileName, newline ~ getLogLine()); } else { // destinatin log file doesn't exist, create one // TODO: check and create directories on the path // write log's header comment write(logFileName, "#Software: Microsoft Internet Information Services 5.0" ~ newline ~ "#Version: 1.0" ~ newline ~ "#Date: 2008-03-31 00:00:19" ~ newline ~ "#Fields: date time c-ip cs-username s-ip s-port cs-method" ~ " cs-uri-stem cs-uri-query sc-status cs(User-Agent)" ~ newline); // write first line of log content append(logFileName, getLogLine()); } } // append new log to destination, in specified time interval repeat(delegate() { // get a random number in the range [5, 20) r = random(5, 20); // append generated log to destination for (int i = 0; i < r; ++i) { append(logFileName, newline ~ getLogLine()); } }, timeInterval, FOREVER); } //=============================================================== // Timer, written by Dennis Kempin //=============================================================== import std.thread; version(Windows) { import std.c.windows.windows; } version(linux) { import std.c.linux.linux; } class Timer: Thread { private void delegate() action; private int waitTime; private bit autoRestart; this(int waitTime, void delegate() action, bit autoRestart=false) { this.action = action; this.waitTime = waitTime; this.autoRestart = autoRestart; } protected this(int waitTime, bit autoRestart=false) { this.waitTime = waitTime; this.autoRestart = autoRestart; } override int run() { sleep(waitTime); execute(); while(autoRestart) { sleep(waitTime); execute(); } return 0; } void execute() { action(); } private void sleep(int time) { version(Windows) { Sleep(time*1000); } version(linux) { usleep(time*1000); } } }
相关推荐
利用java代码实现 生成批量log日志文件
Log4cpp 是一个流行的开源日志库,尤其适用于 C++ 开发者,它提供了丰富的功能,使开发者能够方便地在程序中生成和管理日志文件。本文将详细介绍如何在 Windows 和 Linux 系统中使用 Log4cpp 库来实现日志功能。 **...
这将使安装程序在目标目录下生成一个名为“install.log”的日志文件。 在卸载过程中调用log来卸载文件是一种确保完整性和一致性的方法。当卸载程序读取安装时生成的日志,它可以准确知道哪些文件是在安装过程中被...
"Log4cpp(添加按日期生成日志类)" 提示我们这是一个关于Log4cpp的项目,而且已经进行了扩展,增加了按照日期生成日志文件的功能。Log4cpp是C++的一个日志记录库,它借鉴了Java中的log4j框架,提供了灵活的日志管理...
log4net是一个开放源代码的日志框架,用于.NET平台的应用程序。它基于Apache Logging Services的log4j项目,并进行了扩展和优化,使其更适应.NET环境。log4net提供了一种灵活的日志记录机制,可以将日志信息输出到...
名字生成log脚本exe
自动ping并生成log报告。 默认是ping天津电信DNS,可右键单击后编辑,把219.150.32.132改成你需要去ping的IP即可。 注:尽量不要改文件名和其他参数。
在Java Web开发中,Tomcat是一个广泛使用的应用服务器,它负责运行我们的Servlet和JSP应用程序。日志系统是任何应用程序的重要组成部分,它帮助开发者在调试、监控和问题排查时收集必要的信息。Log4j是Apache的一个...
本文将深入探讨如何利用Log4j生成动态的日志文件名以及动态创建文件夹,帮助开发者更好地管理和分析应用程序的运行状态。 Log4j是一款功能强大的开源日志组件,它允许程序员灵活地控制日志信息的输出级别,如DEBUG...
本文将深入探讨如何使用Log4j生成带有时间戳的日志文件,同时还会涉及到extras包的使用以及一个简单的示例。 1. **Log4j基本概念** - **日志级别**:Log4j支持多种日志级别,包括DEBUG、INFO、WARN、ERROR和FATAL...
"Log4j测试程序" 这个标题表明了这是一个关于Log4j的日志测试项目,Log4j是Java编程语言中的一个开源日志记录框架,广泛用于各种应用程序,它允许开发者灵活地控制日志信息的输出。 **描述解析:** "log4j入门程序...
总的来说,通过理解伪随机数生成和高斯白噪声的特性,我们可以编写程序在VC++环境中生成所需的噪声,并通过可视化工具观察其时域表现。这对于理解和模拟随机过程至关重要,也常用于各种科学和工程计算。
下面是一个简单的`LogDemo`程序示例: ```java import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; public class LogDemo { private static final Log log = LogFactory.get...
Log4j是一个广泛使用的开源日志框架,提供灵活的日志配置和多种级别的日志输出。本文将详细介绍如何在Tomcat服务器环境下使用Log4j接管生成日志文件。 首先,了解Log4j的核心组件: 1. **Logger**:负责生成日志...
在C语言编程中,log函数通常用于执行对数计算,它是数学中的一个重要概念,尤其在科学计算、工程问题以及数据分析等领域广泛应用。C语言标准库提供了数学函数,包括log函数,来帮助程序员处理这类计算。本篇文章将...
在这个配置中,我们定义了两个FileAppender,一个用于接口A(A.log),另一个用于接口B(B.log)。通过设置`log4j.logger`属性,我们可以指定这些接口的日志输出应该被哪个Appender捕获。例如,所有在`...
这段配置中,我们定义了一个名为"RollingFileAppender"的滚动文件追加器,设置日志文件存储路径为"logs"目录下的"log.txt",并按照日期(年-月-日)滚动生成新的日志文件。`datePattern`属性指定了文件名格式,`...
在`testLog4Net`这个测试程序中,可能包含了一个简单的控制台应用程序,该程序执行特定的操作并在执行过程中使用log4Net记录日志。测试可能涉及不同的日志级别,确保正确地记录和输出信息。通过运行程序并检查生成...