h5ai 目录列表程序

h5ai 自己的介绍说自己的是为HTTP WEB服务设计的一款现代化的文件索引,主要面向文件,提供了现代化的可视化界面。他是一款功能强大的文件目录列表程序,由德国开发者 Lars Jung 主导开发,提供多种文件列表呈现方式,支持多种主流WEB服务器,可以在线预览文本,图片,音频,视频。

依赖:PHP 5.5+ and works fine with Apache httpd, lighttpd, nginx and Cherokee

在没有 h5ai 之前,我都使用 nginx 的自带的显示文件列表配置

location / {
    audoindex on;
}

不过不管是 Apache 还是 Nginx 提供的文件列表都是非常简易的,只会显示当前文件夹下的文件,如果都是压缩文件还好,遇到一些多媒体,图片,音频,视频等等就会有一些不便。

安装

h5ai 的安装非常方便,下载,解压,配置 Nginx,配置 DNS,访问即可,如果需要高级功能,可以再配置,主要的配置修改

  • 安装php7.0, sudo apt install php7.0
  • 修改 index 添加 h5ai 的地址, index index.html index.htm /_h5ai/public/index.php;
  • 增加 php 的配置

配置 Nginx,在 /etc/nginx/sites-available/ 下创建 drive.einverne.info

server {
	listen 80;
	listen [::]:80;

	# SSL configuration
	#
	# listen 443 ssl default_server;
	# listen [::]:443 ssl default_server;

	# Add index.php to the list if you are using PHP

	root /var/www/drive.einverne.info/html;
	index index.html index.htm /_h5ai/public/index.php;
	server_name drive.einverne.info;

	location / {
		# First attempt to serve request as file, then
		# as directory, then fall back to displaying a 404.
		# autoindex on;
		try_files $uri $uri/ =404;
	}

	# deny access to .htaccess files, if Apache's document root
	# concurs with nginx's one
	#
	#location ~ /\.ht {
	#	deny all;
	#}
	location ~ \.php$ {
		include snippets/fastcgi-php.conf;
		fastcgi_pass unix:/run/php/php7.0-fpm.sock;
	}
}


# Virtual Host configuration for example.com
#
# You can move that to a different file under sites-available/ and symlink that
# to sites-enabled/ to enable it.
#
#server {
#	listen 80;
#	listen [::]:80;
#
#	server_name example.com;
#
#	root /var/www/example.com;
#	index index.html;
#
#	location / {
#		try_files $uri $uri/ =404;
#	}
#}

再将域名的 DNS 配置 A 记录解析到 VPS

在配置的 root 目录 /var/www/drive.einverne.info/html

wget https://release.larsjung.de/h5ai/h5ai-0.29.0.zip
unzip h5ai-0.29.0.zip

然后刷新浏览器即可。 哦对了要确保安装了 PHP 7.0 的哈。

配置

h5ai 安装完成之后,可以到 domain/_h5ai/public/index.php 查看 h5ai 的相关信息,默认密码为空。页面中可以查看当前 h5ai 开启的选项。

Ubuntu 16.04 以上

apt-get -y install zip
apt-get -y install ffmpeg   # 视频缩略图
apt-get -y install imagemagick   # PDF 缩略图

增加密码保护

编辑文件 /_h5ai/public/index.php ,在底部增加:

function auth ()
{
    $valid_passwords = array ("账号" => "密码");
    $valid_users = array_keys($valid_passwords);

    $user = $_SERVER['PHP_AUTH_USER'];
    $pass = $_SERVER['PHP_AUTH_PW'];

    $validated = (in_array($user, $valid_users)) && ($pass == $valid_passwords[$user]);

    if (!$validated) {
      header('WWW-Authenticate: Basic realm="My Realm"');
      header('HTTP/1.0 401 Unauthorized');
      die ("Not authorized");
    }
}

在头部 <?php 的下一行,增加

auth();

options.json 开启更多功能

位于 _h5ai/private/conf 目录下。

打包下载: 搜索 “download” 127 行,enabled 由 false 改为 true。

文件信息及二维码: 搜索 “info” 185 行,enabled 由 false 改为 true。

默认简体中文: 搜索 “l10n” 202 行,enabled 由 false 改为 true。

文件及文件夹多选: 搜索 “select” 323 行,enabled 由 false 改为 true。

还有二维码等等功能,看一眼配置基本就能明白。

修改 domain/_h5ai/public/index.php 页面的默认密码:

首先生成自定义 sha512 密码:http://md5hashing.net/hashing/sha512 然后搜索 “passhash”,大概第 10 行,将其密码改成自己生成的。

注意

如果使用 LNMP 一键安装的环境,可能需要修改 php 配置,vim /usr/local/php/etc/php.ini 搜索 scandir、exec、passthru,将其从被禁用的函数中删除。


2017-12-20 linux , php , nginx , h5ai , file

最有用的 Chrome 快捷键提高数倍效率

我常使用的 Chrome 默认快捷键,Chrome 默认的快捷键已经非常全面,几乎可以不用鼠标操作浏览器的一切行为,我总以为使用不管是使用鼠标还是手势来进行网页浏览是非常耗时的一件事情,如果能够像 Vim 的哲学一样,不用离开键盘来浏览网页,不仅提高的是效率,也能够培养起,不再做内容的消费者,而是做内容的产生者这样的意识。

快捷键 作用
Alt + Left back current page
Alt + Right Forward current page
Ctrl + H 在新标签页打开历史记录
Ctrl + J 在新标签页打开下载记录
Ctrl + K 将光标定位到 Omnibox ,也就是 Chrome 自定搜索
Ctrl + L 将光标快速定位到地址栏
Ctrl + T 新标签页
Ctrl + Shift + T 重新打开关闭的标签页
Ctrl + W 快速关闭当前标签页
Ctrl + P 打印 或者 保存为 PDF
Ctrl + N 新开浏览器窗口
Ctrl + Shift + N 新开隐身窗口
Ctrl + R 或者 F5 刷新
Ctrl + U 查看源码
Ctrl + Tab 挨个切换标签页
Ctrl + 单击 在新标签页打开

以上就是几乎每天都会用到的一些快捷键。

插件的快捷键

Vimium

下载地址:https://chrome.google.com/webstore/detail/vimium/dbepggeogbaibhgnhhndojpepiihcmeb

使用 shift + / 查看所有快捷键,绝大部分都是 Vim 的快捷键,不在赘述。

页面内跳转

快捷键 作用
j 向下
k 向上滚动
d 向下翻页
u 向上翻页
f 显示快捷键导航
F 新标签页打开此链接
H 回退
L Forward
b 弹出 vomnibar 来打开收藏夹中的网址
B 新标签页打开
o 打开搜索工具栏,在收藏夹,历史记录中搜索,如果没有匹配则直接使用默认的搜索引擎搜索
O 功能和o一致,区别为在新标签页中显示搜索结果
G 页面底部
r 刷新
yy 复制当前页地址
gi 将光标放到第一个输入框中,在Google搜索结果页面非常有用
gg 顶部

标签页

快捷键 作用
J或gT 左边的标签页
K或gt 右边的标签页
t 创建新标签页
x 关闭当前的标签页
X 恢复刚刚关闭的标签页
g0 跳转到第一个标签页
g$ 跳转到最后一个标签页

其他有用快捷键

快捷键 作用
Ctrl + Shift + W 关闭当前浏览器窗口

2017-12-19 chrome , shortcut

每天学习一个命令:curl 命令行下载工具

curl 命令是一个利用URL规则在命令行下工作的文件传输工具。它支持文件的上传和下载,所以是综合传输工具,但按传统,习惯称curl为下载工具。作为一款强力工具,curl支持包括HTTP、HTTPS、ftp等众多协议,还支持POST、cookies、认证、从指定偏移处下载部分文件、用户代理字符串、限速、文件大小、进度条等特征。

例子

URL 访问

下载单个网址,默认将输出打印到标准输出

curl www.google.com

保存到文件

如果需要将页面源码保存到本地,可以使用-o参数:

-o 将文件保存到 -o 指定的文件名
-O 将文件保存到默认文件名

curl -o google.html www.google.com

重定向

默认情况下CURL不会发送HTTP Location headers(重定向).当一个被请求页面移动到另一个站点时,会发送一个HTTP Loaction header作为请求,然后将请求重定向到新的地址上。

curl -L google.com

断点续传

通过使用-C选项可对大文件使用断点续传功能

查看Header

使用 -i 或者 --include 参数查看返回Header

curl -i google.com

使用 -i 参数,页面相应头header和页面相应body 一起返回,如果只想查看 header,可以使用 -I 或者 --head

表单提交

GET 提交直接将参数添加到 URL后

POST 提交时

curl -X POST --data 'keyword=value' https://httpbin.org/post

其他 HTTP 方法通过 -X 参数指定即可

curl -X DELETE url

curl -X PUT --data 'key=value' url

文件上传

curl -T file.txt url

HTTPS 支持

curl -E mycert.pem https://url

添加请求头

curl -H ‘Content-Type:application/json' -H 'Authorization: bearer valid_token' URL

-c参数保存请求返回 Cookie,本地存储文件

curl -b cook_file.txt -c response_cookie.txt URL

上传FTP

通过 -T 选项可指定本地文件上传到FTP服务器

curl -u ftpuser:ftppassword -T file.txt ftp://ftp.server
curl -u ftpuser:ftppassword -T "{file1, file2}" ftp://ftp.server

总的来说,curl 的用法比较普通,最常见的也就是用来下载文件,或者直接查看Header,还有在命令行下发送 GET或者 POST 请求,其他用法倒也是有,不过日常并没有经常使用到。

外延 wget

wget是一个下载文件的工具,它用在命令行下。对于Linux用户是必不可少的工具,我们经常要下载一些软件或从远程服务器恢复备份到本地服务器。wget支持HTTP,HTTPS和FTP协议,可以使用HTTP代理。

wget https://www.google.com

外延 axel

Axel是 Linux 下一款不错的 HTTP 或 FTP 高速下载工具。支持多线程下载、断点续传,且可以从多个地址或者从一个地址的多个连接来下载同一个文件,适合网速不给力时多线程下载以提高下载速度。

使用10个线程同时下载文件

axel -n 10 url

外延 mwget

多线程版本 wget,同时使用5个线程下载

mwget -n 5 url

reference


2017-12-18 linux , curl , command , network

Trello 简单使用

新工具 Trello,说新工具也好,新的规划板也好,Trello 已经代替了我制定规划的其他应用,我曾经尝试过无数的时间管理项目管理工具,没有一个让我有使用 Trello 的舒畅感。

Trello 是什么

Trello 自己的介绍说自己是一个基于网页端的项目管理应用。但在我个人看来,作为个人的 Board,他是一个极好的GTD 管理工具,如果是多人使用,那就是一个很好的协作管理工具。

Trello 怎么用

怎么用其实是一个非常个人的习惯问题,他作为一个效率工具提供了各种可能,不仅能够作为简单的待办事项管理工具,甚至能够在十几或者几十人的团队中担任项目管理的工具。

这里就要说到 Trello 中的几个概念,看板、列表、卡片。幸而 Trello 的官方介绍非常详细,连中文译名也是朗朗上口,大赞。如果想要了解 Trello 如何得此名字可以看这篇文章

一个 Trello 看板是装满卡片的各种列表的列表,它属于一个团队或你本人。可以把他看成是一个黑板,或者一个 Working Area,或者叫 Workspace。

Trello 的列表是承载卡片的容器,不同的工作团队可以根据自己的 Workflow 来定制自己的列表,如果个人作为一个 GTD 的工具,使用官方推荐的,建立三个列表—-Todo,Doing,Done,也是不错的。

最后 Trello 的卡片,是 Trello 的核心,卡片可以看做是一项待办事项,也可以看做是一个任务,甚至可以看成一个提醒,更或者可以在卡片内部定义自己的更加具体的待办事项(Checklist)。

卡片承载的内容可以很简单,也可以非常复杂,卡片中不仅包括标题,还包括任务描述,附件,清单(Checklist),评论,可以对卡片添加标签,添加到期时间,也可以添加其他成员,甚至可以订阅该卡片的通知。一个卡片承载了非常多的功能,但是使用起来就可以根据不同的应用场景来调整。而这篇文章更是直接使用 Markdown 在卡片描述中完成的。

trello card

更加详细的内容可以看:https://trello.com/tour

Trello 团队使用 150 多个看板来管理产品进度1

Project management apps turn ambitious ideas into workable plans.

评价

跨平台

跨平台已经成为了我选用工具首选的因素,Web,Android,iOS, 是必须要支持的,其次三大桌面平台,如果有支持当然好,没有客户端,Web App 已经要足够精致和易用。垃圾的 Evernote 就是 Web App 有些烂,还不提供 Linux 版。

足够快

想当年 Chrome 出来的时候,主打的第一个特性就是快,对于一个入口应用,必须要足够的快,使用过程中不能有感知的卡顿,否则就失去了这个工具的意义,工具都是为了提高效率而诞生的,自身不能成为影响效率的因素。幸而使用 Trello 的过程中,他也一如他宣传的那样,几乎不用刷新,实时同步,毫无卡顿。

高扩展

Trello 作为一款看板应用已经被数以千计的公司使用,也得到了无数的三方应用的支持,虽然非企业版可支持的扩展 (Power up)限制为一个,但个人使用 Board,List,Card 等基本功能都是毫无限制的,可以通过 Zapier 或者 IFTTT 集成更多的自动化的工作流进来,比如在 Google Calendar 上新建一个日历时,自动在 List 中创建一个 Card,在 Card 中新建一篇内容时自动创建一个 Evernote 笔记等等,因为开放了 API,无数的可能性,都会诞生。

邮件之于Gmail,那么卡片就之于Trello,每一封邮件可能有自己的标签,Trello 中的卡片也有标签,默认提供了很多不同颜色的标签,用来自定义卡片紧急程度也好,定义卡片类型也好,也提供了很多可能。Trello 还提供了 Sticker 这样有趣的功能,可以将不同的 Sticker 贴到 卡片上,很有趣。

有效的通知

Trello 作为一个项目管理或者时间管理的工具,提醒是必不可少的,Trello 的通知方式有很多,应用中通知,邮件通知,浏览器桌面通知,移动设备推送通知,所有的通知在所有的设备上都保持同步。

Trello 更加有效的是订阅模式,如果只对某一个 任务(Card)感兴趣,可以只关心该卡片的变动通知。

如果你还不知道怎么开始的话,可以简单的看看这个

http://help.trello.com/category/694-category

使用小技巧

快速新建 List

在看板中双击就能在当前位置新建 List,输入名字就能够快速建立 List

快速插入图片

如果在网站上浏览到一个图片,可以右键选择复制图片,然后在 Trello 的卡片中可以使用 Ctrl+V 来插入图片。或者如果你更愿意使用拖拽,也可以直接将网页中的图片拖拽到卡片中。

充分利用卡片中的 Checklist

Trelle 的卡片功能丰富,你可以拿卡片做任何想做的事情,但是别忘了你还可以插入一个 Checklist,可以在 Checklist 中填入每一步待办事项,然后做完之后依次check。即使卡片没有展开,在列表的缩略图上也能清晰地看到卡片有多少项任务没有做完。

Trello Gold

Trello Gold 类似于其他网站的高级会员,可以通过购买获取,也可以通过邀请获取。使用 Gold 会员有如下几个好处:

  • 使用额外的 Stickers
  • 可以自定义背景图片
  • 更大的附件,单文件最大可以250M
  • 上传自定义emoji
  • 保存搜索结果

对于普通使用来说,这些额外的附加效果几乎可以忽略,都是一些低频次操作。但如果你是重度用户不妨先邀请身边的好友来先体验下 Gold 版的 Trello。比如你可以邀请小伙伴一起制定计划:

Trello screenshot demo

另外我有几个公开的 board,如果感兴趣可以加入:

reference


2017-12-13 todo , web , 产品体验 , plan , gtd , checklist , list , card

优雅地使用命令行

使用快捷键

Ctrl+a Ctrl+e Ctrl+u Ctrl+r

Ctrl+n Ctrl+p 等等

更多的快捷键和 bash 的内容可以参考这篇

终端显示 Git 分支

绝大多数情况下会在终端来管理 git 项目,对 git 项目最好能够有一个直观的显示,包括当前的分支,修改的内容,命令行空间比较小,但是也能够显示分支名和是否有修改,推荐使用

oh-my-zsh

使用别名

把每天要使用5次以上的命令都制作别名保存到 bashrc 或者 zshrc 中

alias vi='vim'

使用 Terminator 或者 Tmux

如果经常切换不同的终端窗口执行不同的任务,那么就需要考虑使用顺手的多窗口或者支持分屏(panel)的终端,推荐使用 Tmux,配合快捷键无比顺畅。

Tmux 的内容可以参考这个

善用 Linux 命令

除却常用的查找文件、浏览文件命令等等之外,善用命令行中的 Tab 自动补全,通配符等等。

cat, grep

通过文件名查找

sudo find -name <filename> path_to_search

滚动查看大文件

less path_to_file

当前路径下打开文件管理器

nemo .

树形结构展开当前目录结构,包括子目录和文件

tree

流式读取一个文件,实时日志文件

tail -f filename

管道机制

Unix 哲学中,每个程序都足够小,只做一件事情,并将其做到最好。Bash 提供的管道机制 (|) 可以将命令的输出作为另一个命令的输入,结合两个或者多个命令,比如最简单的例子,ls 是将目录下文件列出, grep 命令是搜索包含指定正则的行,结合两者

ls ~ | grep word

就可以过滤HOME目录下,包含 word 的文件

通配符

* 星号字符匹配任意长度,比如删除文件夹下,指定文件

rm morning*.jpg

这样就删除了当前目录下所有 morning 开头的 jpg 文件,使用 rm 命令时一定要注意确认

输出重定向

> 字符可以将一个命令的输出重定向到一个文件或者另一个命令的输入,一般情况下命令会有一些输出结果

tree . > file.txt

可以将当前文件目录结构输出到文件 file.txt 中。

> 会覆盖输出的文件 >> 用来追加到文件末尾。

后台执行

Bash 默认情况下会立即执行当前键入的每一条命令,通常我们就是这样要求终端的,但是如果想要某一些应用在后台长时间执行,可以使用 & 操作符

./long_time_task.sh &

可以在后台执行一个长时间任务

显示监控和终止进程

使用 htop 来查看系统资源,以及对进程进行管理,当然如果熟悉 ps 也可以使用 ps 来查看

使用高效的编辑器

大型 Java 项目可以考虑使用 JetBrains 系列产品,对于 Python, Bash 等脚本语言可以考虑使用 vim

Other

  • RedShift:在电脑屏幕上放上这个会让你睡得更好。
  • Self Control:这个可以帮助你控制你自己的习惯,避免在FB,Twitter上流连忘返。

reference


2017-12-12 liux , command , git , tmux

Tmux Plugins


layout: post title: “Tmux 的插件们” tagline: “” description: “介绍目前我在使用的 Tmux 插件们” category: 学习笔记 tags: [tmux, linux, terminal,] last_updated: –

Vim 有插件管理,zsh 也有插件管理,那当然 Tmux 肯定有插件管理,其实学习 Tmux 的过程中,和 Vim 当时一样,所有的拷贝,粘贴的内容都是在 Tmux 和 Vim 的内部,和外部操作系统的粘贴板完全隔离了,我就是为了解决这个问题,才接触到了 Tmux Plugin Manager

Tmux Plugin Manager

安装的方法,在 GitHub 的页面非常清楚,git clone 项目,在 .tmux.conf 文件中加入配置,重新加载配置即可。

# List of plugins
set -g @plugin 'tmux-plugins/tpm'
set -g @plugin 'tmux-plugins/tmux-sensible'

# Other examples:
# set -g @plugin 'github_username/plugin_name'
# set -g @plugin 'git@github.com/user/plugin'
# set -g @plugin 'git@bitbucket.com/user/plugin'

# Initialize TMUX plugin manager (keep this line at the very bottom of tmux.conf)
run '~/.tmux/plugins/tpm/tpm'

新添加插件只需要,在配置文件中增加一行

set -g @plugin '...'

这样,再使用 <prefix> + I 大写的 I (Install) 来安装新插件

卸载插件时,配置文件中移除一行,并使用 <prefix> + alt + u (uninstall) 来卸载。

更新快捷键是 <prefix> + u

tmux-yank

.tmux.conf 中加入

set -g @plugin 'tmux-plugins/tmux-yank'

然后使用 <prefix> + I 来安装 tmux-yank

Linux 平台下需要安装依赖 xsel 或者 xclip

sudo apt-get install xsel # or xclip

快捷键

在 normal mode 下

<prefix> + y 来将命令行内容拷贝到 clipboard 系统粘贴板。

<prefix> + Y 将当前 panel 的 working directory 拷贝到粘贴板

在 copy mode 下

y 拷贝到系统粘贴板

Y 将选中的内容,粘贴到命令行


2017-12-08

log4j 配置

Log4j 是一个可靠的、高效的、快速可扩展的日志框架,Log4j 使用 Java 开发,已经被移植到了很多主流语言,比如 C, C++, Perl, Python, Ruby 等等。Log4j 可以通过外部文件配置来定义行为,Log4j 为日志输出提供了不同的目的地,比如可以将日志输出到控制台,文件,数据库等等。我们也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,能够更加细致地控制日志的生成过程。这一切都可以通过一个配置文件来灵活地进行配置,而不需要修改应用代码。Log4j是Apache的一个开放源代码项目。

在应用程序中添加日志记录总的来说基于三个目的:

  • 监视代码中变量的变化情况,周期性的记录到文件中供其他应用进行统计分析工作
  • 跟踪代码运行时轨迹,作为日后审计的依据
  • 担当集成开发环境中的调试器的作用,向文件或控制台打印代码的调试信息

Log4j 主要有三个组件:

  • Loggers(记录器) ,作用就是用来记录日志
  • Appenders (输出源) ,用来将采集的日志信息发送到不同的目的地
  • Layouts(布局),用于格式化输出日志

综合使用这三个组件可以轻松的记录信息的类型和级别,并可以在运行时控制日志输出的样式和位置。

Log4j 的特性:

  • 线程安全
  • 为速度优化
  • 同一个记录器支持不同的输出
  • 支持多语言
  • 日志的行为可以通过配置文件在运行时使用
  • 支持不同的 LEVEL
  • 日志的输出可以通过 Layout 类来改变
  • 日志的输出途径可以通过修改 Appender 接口来定义

通常,我们都提供一个名为 log4j.properties 的文件,该文件以 key-value 的方式进行配置。默认情况下,LogManager 会在 CLASSPATH 目录下寻找 log4j.properties 这个文件名。

简单例子

# Define the root logger with appender X
log4j.rootLogger = DEBUG, X

# Set the appender named X to be a File appender
log4j.appender.X=org.apache.log4j.FileAppender
log4j.appender.X.File=${log}/log.out

# Define the layout for X appender
log4j.appender.X.layout=org.apache.log4j.PatternLayout
log4j.appender.X.layout.conversionPattern=%d{yyyy-MM-dd HH:mm:ss} %p [%t] %C{1}.%M(%F:%L) - %m%n

这个例子定义了

  • root logger 的level 是 DEBUG,并且 DEBUG 附加到一个名为 X 的 Appender 上
  • 设置 X Appender
  • 然后设置 X 的 layout

Maven 依赖

在 maven 的 pom.xml dependency 下添加:

<!-- sl4j -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.21</version>
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.7.21</version>
</dependency>
<!-- log4j -->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

slf4j(Simple Logging Facade for Java) 不是一个真正的日志实现,而是一个抽象层,它允许在后台使用任意一个日志类库。slf4j 使得代码能够独立于任意一个特定的日志API。 SLF4J API的特性占位符(place holder),在代码中表示为“{}”的特性。占位符是一个非常类似于在String的format()方法中的%s,因为它会在运行时被某个提供的实际字符串所替换。这不仅降低了你代码中字符串连接次数,而且还节省了新建的String对象。

然后在 CLASSPATH 下添加 log4j.properties 文件。

#config root logger  
log4j.rootLogger = INFO,system.out  
log4j.appender.system.out=org.apache.log4j.ConsoleAppender  
log4j.appender.system.out.layout=org.apache.log4j.PatternLayout  
log4j.appender.system.out.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %p [%t] %C{1}.%M(%F:%L) - %m%n
  
#config this Project.file logger  
log4j.logger.APPENDER_NAME.file=INFO,APPENDER_NAME.file.out  
log4j.appender.APPENDER_NAME.file.out=org.apache.log4j.DailyRollingFileAppender  
log4j.appender.APPENDER_NAME.file.out.File=logContentFile.log  
log4j.appender.APPENDER_NAME.file.out.layout=org.apache.log4j.PatternLayout  

在 Java 代码中使用 slf4j

private static final Logger logger = LoggerFactory.getLogger(Server.class);
logger.info("now {}" , "starting server");

Log4j 支持两种配置文件格式,一种是XML格式的文件,一种是Java properties(key=value)【Java特性文件(键=值)】。先介绍使用Java特性文件做为配置文件的方法

配置详细介绍

配置 Logger   

Loggers 组件在此系统中被分为五个级别:DEBUG、INFO、WARN、ERROR和FATAL。这五个级别是有顺序的

DEBUG < INFO < WARN < ERROR < FATAL

分别用来指定这条日志信息的重要程度,这里Log4j有一个规则:假设Loggers 级别为 P,如果在Loggers中发生了一个级别Q 比 P 高,则记录,否则就不记录。

比如,你定义的级别是info,那么error和warn的日志可以显示而比他低的debug信息就不显示了。

配置根Logger

其语法为:

  log4j.rootLogger = [ level ] , appenderName1, appenderName2, … # level : 是日志记录的优先级,分为OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL或者您定义的级别。Log4j建议只使用四个级别,优先级从高到低分别是ERROR、WARN、INFO、DEBUG。通过在这里定义的级别,您可以控制到应用程序中相应级别的日志信息的开关。比如在这里定义了INFO级别,则应用程序中所有DEBUG级别的日志信息将不被打印出来。

  appenderName:就是指定日志信息输出到哪个地方。可以同时指定多个输出目的地。

例如:log4j.rootLogger=info,A1,B2,C3

  

配置日志信息输出目的地

Log4j 日志系统允许把日志输出到不同的地方,如控制台(Console)、文件(Files)、根据天数或者文件大小产生新的文件、以流的形式发送到其它地方等等。

其语法为:

log4j.appender.appenderName = fully.qualified.name.of.appender.class 
log4j.appender.appenderName.option1 = value1 
log4j.appender.appenderName.optionN = valueN 

其中, Log4j 提供的 appender 有以下几种:

  • org.apache.log4j.ConsoleAppender 输出到控制台
  • org.apache.log4j.FileAppender 输出到文件
  • org.apache.log4j.DailyRollingFileAppender 输出到每天产生一个日志文件
  • org.apache.log4j.RollingFileAppender 文件大小到达指定尺寸的时候产生一个新的文件,可通过 log4j.appender.R.MaxFileSize=100KB 设置文件大小,还可通过 log4j.appender.R.MaxBackupIndex=1 设置为保存一个备份文件
  • org.apache.log4j.WriterAppender 将日志信息以流格式发送到任意指定的地方

例:

log4j.appender.stdout=org.apache.log4j.ConsoleAppender 

定义一个名为 stdout 的输出目的地, 输出到控制台。

其语法为:

log4j.appender.appenderName = fully.qualified.name.of.appender.class

“fully.qualified.name.of.appender.class” 可以指定下面五个目的地中的一个:

  • org.apache.log4j.ConsoleAppender(控制台)
  • org.apache.log4j.FileAppender(文件)
  • org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件)
  • org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件)
  • org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方)

输出目的地的选项,可以通过如下语法指定

log4j.appender.appenderName.option = valueN

ConsoleAppender选项

Threshold=WARN:指定日志消息的输出最低层次。 ImmediateFlush=true:默认值是true,意谓着所有的消息都会被立即输出。 Target=System.err:默认情况下是:System.out,指定输出控制台

FileAppender 选项

Threshold=WARN:指定日志消息的输出最低层次。 ImmediateFlush=true:默认值是true,意谓着所有的消息都会被立即输出。 File=mylog.txt:指定消息输出到mylog.txt文件。 Append=false:默认值是true,即将消息增加到指定文件中,false指将消息覆盖指定的文件内容。

Java web 项目里面的日志的位置配置支持变量

如果是要指定日志文件的位置为D盘下的log.txt文件。

log4j.appender.APPENDER_NAME.file.out.File=d:\\log.txt

如果指定日志文件的位置为当前的tomcat的工作目录下的某个文件

log4j.appender.APPENDER_NAME.file.out.File=${catalina.home}/logs/logs_tomcat.log

DailyRollingFileAppender 选项

Threshold=WARN:指定日志消息的输出最低层次。

ImmediateFlush=true:默认值是true,意谓着所有的消息都会被立即输出。

File=mylog.txt:指定消息输出到mylog.txt文件。

Append=false:默认值是true,即将消息增加到指定文件中,false指将消息覆盖指定的文件内容。

DatePattern=’.’yyyy-ww:每周滚动一次文件,即每周产生一个新的文件。当然也可以指定按月、周、天、时和分。即对应的格式如下:

  • ’.’yyyy-MM: 每月
  • ’.’yyyy-ww: 每周
  • ’.’yyyy-MM-dd: 每天
  • ’.’yyyy-MM-dd-a: 每天两次
  • ’.’yyyy-MM-dd-HH: 每小时
  • ’.’yyyy-MM-dd-HH-mm: 每分钟

RollingFileAppender 选项

Threshold=WARN:指定日志消息的输出最低层次。 ImmediateFlush=true:默认值是true,意谓着所有的消息都会被立即输出。 File=mylog.txt:指定消息输出到mylog.txt文件。 Append=false:默认值是true,即将消息增加到指定文件中,false指将消息覆盖指定的文件内容。 MaxFileSize=100KB: 后缀可以是KB, MB 或者是 GB. 在日志文件到达该大小时,将会自动滚动,即将原来的内容移到mylog.log.1文件。 MaxBackupIndex=2:指定可以产生的滚动文件的最大数。

实际应用:

  log4j.appender.A1=org.apache.log4j.ConsoleAppender //这里指定了日志输出的第一个位置A1是控制台ConsoleAppender   

配置日志信息的格式

有时用户希望根据自己的喜好格式化自己的日志输出。Log4j可以在Appenders的后面附加Layouts来完成这个功能。Layouts提供了四种日志输出样式,如根据HTML样式、自由指定样式、包含日志级别与信息的样式和包含日志时间、线程、类别等信息的样式等等。

其语法表示为:

  org.apache.log4j.HTMLLayout 以HTML表格形式布局   org.apache.log4j.PatternLayout 可以灵活地指定布局模式   org.apache.log4j.SimpleLayout 包含日志信息的级别和信息字符串   org.apache.log4j.TTCCLayout 包含日志产生的时间、线程、类别等等信息

配置时使用方式为:

  log4j.appender.appenderName.layout = fully.qualified.name.of.layout.class   log4j.appender.appenderName.layout.option1 = value1

  log4j.appender.appenderName.layout.option = valueN

“fully.qualified.name.of.layout.class” 可以指定下面4个格式中的一个:

  • org.apache.log4j.HTMLLayout(以HTML表格形式布局),
  • org.apache.log4j.PatternLayout(可以灵活地指定布局模式),
  • org.apache.log4j.SimpleLayout(包含日志信息的级别和信息字符串),
  • org.apache.log4j.TTCCLayout(包含日志产生的时间、线程、类别等等信息)

输出格式

Log4J 采用类似 C 语言中的 printf 函数的打印格式格式化日志信息,打印参数如下:

%m 输出代码中指定的消息
%p 输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL
%r 输出自应用启动到输出该log信息耗费的毫秒数
%c 输出所属的类目,通常就是所在类的全名
%t 输出产生该日志事件的线程名
%n 输出一个回车换行符,Windows平台为“\r\n”,Unix平台为“\n”
%d 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如: %d{yyyy MMM dd HH:mm:ss,SSS} ,输出类似: 2002 年 10 月 18 日 22 : 10 : 28 , 921 
%l 输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数。 

格式化例子:

log4j.appender.APPENDER_NAME.file.out.layout.ConversionPattern=%d{yyyy MMM dd HH:mm:ss,SSS}%5p{ \%F\:\%L }-%m%n

注意:

参数中间可能会有一些数字,比如:%5p 它的意思就是在输出此参数之前加入多少个空格,还有就是里面的“\”的作用是转义字符

HTMLLayout 选项

LocationInfo=true:默认值是false,输出java文件名称和行号 Title=my app file: 默认值是 Log4J Log Messages.

PatternLayout 选项

ConversionPattern=%m%n :指定怎样格式化指定的消息。

XMLLayout 选项

LocationInfo=true:默认值是false,输出java文件和行号

实际应用:

log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-4r %-5p %d{yyyy-MM-dd HH:mm:ssS} %c %m%n

这里需要说明的就是日志信息格式中几个符号所代表的含义:

%p: 输出日志信息优先级,即DEBUG,INFO,WARN,ERROR,FATAL,
%d: 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyy MMM dd HH:mm:ss,SSS},输出类似:2002年10月18日 22:10:28,921
%r: 输出自应用启动到输出该log信息耗费的毫秒数
%c: 输出日志信息所属的类目,通常就是所在类的全名
%t: 输出产生该日志事件的线程名
%l: 输出日志事件的发生位置,相当于%C.%M(%F:%L)的组合,包括类目名、发生的线程,以及在代码中的行数。举例:Testlog4.main(TestLog4.java:10)
%x: 输出和当前线程相关联的NDC(嵌套诊断环境),尤其用到像java servlets这样的多客户多线程的应用中。
%%: 输出一个"%"字符
%F: 输出日志消息产生时所在的文件名称
%L: 输出代码中的行号
%m: 输出代码中指定的消息,产生的日志具体信息
%n: 输出一个回车换行符,Windows平台为"\r\n",Unix平台为"\n"输出日志信息换行

可以在%与模式字符之间加上修饰符来控制其最小宽度、最大宽度、和文本的对齐方式。如:

  1. %20c:指定输出category的名称,最小的宽度是20,如果category的名称小于20的话,默认的情况下右对齐。
  2. %-20c:指定输出category的名称,最小的宽度是20,如果category的名称小于20的话,”-“号指定左对齐。
  3. %.30c:指定输出category的名称,最大的宽度是30,如果category的名称大于30的话,就会将左边多出的字符截掉,但小于30的话也不会有空格。
  4. %20.30c:如果category的名称小于20就补空格,并且右对齐,如果其名称长于30字符,就从左边交远销出的字符截掉。

这里上面三个步骤是对前面 Log4j 组件说明的一个简化;下面给出一个具体配置例子,在程序中可以参照执行:

  log4j.rootLogger=INFO,A1,B2   log4j.appender.A1=org.apache.log4j.ConsoleAppender   log4j.appender.A1.layout=org.apache.log4j.PatternLayout   log4j.appender.A1.layout.ConversionPattern=%-4r %-5p %d{yyyy-MM-dd HH:mm:ssS} %c %m%n

根据上面的日志格式,某一个程序的输出结果如下:

0  INFO 2003-06-13 13:23:46968 ClientWithLog4j Client socket: Socket[addr=localhost/127.0.0.1,port=8002,localport=2014]
 DEBUG 2003-06-13 13:23:46984 ClientWithLog4j Server says: 'Java server with log4j, Fri Jun 13 13:23:46 CST 2003'
16  DEBUG 2003-06-13 13:23:46984 ClientWithLog4j GOOD
16  DEBUG 2003-06-13 13:23:46984 ClientWithLog4j Server responds: 'Command 'HELLO' not understood.'
16  DEBUG 2003-06-13 13:23:46984 ClientWithLog4j HELP
16  DEBUG 2003-06-13 13:23:46984 ClientWithLog4j Server responds: 'Vocabulary: HELP QUIT'
16  DEBUG 2003-06-13 13:23:46984 ClientWithLog4j QUIT
  1. 当输出信息于回滚文件时

log4j.appender.ROLLING_FILE=org.apache.log4j.RollingFileAppender //指定以文件的方式输出日志 log4j.appender.ROLLING_FILE.Threshold=ERROR log4j.appender.ROLLING_FILE.File=rolling.log //文件位置,也可以用变量${java.home}、rolling.log log4j.appender.ROLLING_FILE.Append=true log4j.appender.ROLLING_FILE.MaxFileSize=10KB //文件最大尺寸 log4j.appender.ROLLING_FILE.MaxBackupIndex=1 //备份数 log4j.appender.ROLLING_FILE.layout=org.apache.log4j.PatternLayout log4j.appender.ROLLING_FILE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n   

Log4j比较全面的配置

LOG4J的配置之简单使它遍及于越来越多的应用中了:Log4J配置文件实现了输出到控制台、文件、回滚文件、发送日志邮件、输出到数据库日志表、自定义标签等全套功能。

log4j.rootLogger=DEBUG,CONSOLE,FILE,ROLLING_FILE,SOCKET,LF5_APPENDER,MAIL,DATABASE,A1,im 
log4j.addivity.org.apache=true 

# 应用于控制台 
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender 
log4j.appender.Threshold=DEBUG 
log4j.appender.CONSOLE.Target=System.out 
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout 
log4j.appender.CONSOLE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n 
#log4j.appender.CONSOLE.layout.ConversionPattern=[start]%d{DATE}[DATE]%n%p[PRIORITY]%n%x[NDC]%n%t[thread] n%c[CATEGORY]%n%m[MESSAGE]%n%n 

#应用于文件 
log4j.appender.FILE=org.apache.log4j.FileAppender 
log4j.appender.FILE.File=file.log 
log4j.appender.FILE.Append=false 
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout 
log4j.appender.FILE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n 
# Use this layout for LogFactor 5 analysis 

# 应用于文件回滚 
log4j.appender.ROLLING_FILE=org.apache.log4j.RollingFileAppender 
log4j.appender.ROLLING_FILE.Threshold=ERROR 
log4j.appender.ROLLING_FILE.File=rolling.log //文件位置,也可以用变量${java.home}、rolling.log
log4j.appender.ROLLING_FILE.Append=true //true:添加 false:覆盖
log4j.appender.ROLLING_FILE.MaxFileSize=10KB //文件最大尺寸
log4j.appender.ROLLING_FILE.MaxBackupIndex=1 //备份数
log4j.appender.ROLLING_FILE.layout=org.apache.log4j.PatternLayout 
log4j.appender.ROLLING_FILE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n

#应用于socket 
log4j.appender.SOCKET=org.apache.log4j.RollingFileAppender 
log4j.appender.SOCKET.RemoteHost=localhost 
log4j.appender.SOCKET.Port=5001 
log4j.appender.SOCKET.LocationInfo=true 
# Set up for Log Facter 5 
log4j.appender.SOCKET.layout=org.apache.log4j.PatternLayout 
log4j.appender.SOCET.layout.ConversionPattern=[start]%d{DATE}[DATE]%n%p[PRIORITY]%n%x[NDC]%n%t[thread]%n%c[CATEGORY]%n%m[MESSAGE]%n%n

# Log Factor 5 Appender 
log4j.appender.LF5_APPENDER=org.apache.log4j.lf5.LF5Appender 
log4j.appender.LF5_APPENDER.MaxNumberOfRecords=2000 

# 发送日志给邮件 
log4j.appender.MAIL=org.apache.log4j.net.SMTPAppender 
log4j.appender.MAIL.Threshold=FATAL 
log4j.appender.MAIL.BufferSize=10 
log4j.appender.MAIL.From=web@gmail.com
log4j.appender.MAIL.SMTPHost=www.gmail.com
log4j.appender.MAIL.Subject=Log4J Message 
log4j.appender.MAIL.To=web@gmail.com
log4j.appender.MAIL.layout=org.apache.log4j.PatternLayout 
log4j.appender.MAIL.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n 
# 用于数据库 
log4j.appender.DATABASE=org.apache.log4j.jdbc.JDBCAppender 
log4j.appender.DATABASE.URL=jdbc:mysql://localhost:3306/test 
log4j.appender.DATABASE.driver=com.mysql.jdbc.Driver 
log4j.appender.DATABASE.user=root 
log4j.appender.DATABASE.password= 
log4j.appender.DATABASE.sql=INSERT INTO LOG4J (Message) VALUES ('[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n') 
log4j.appender.DATABASE.layout=org.apache.log4j.PatternLayout 
log4j.appender.DATABASE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n

log4j.appender.A1=org.apache.log4j.DailyRollingFileAppender 
log4j.appender.A1.File=SampleMessages.log4j 
log4j.appender.A1.DatePattern=yyyyMMdd-HH'.log4j' 
log4j.appender.A1.layout=org.apache.log4j.xml.XMLLayout 

#自定义Appender 
log4j.appender.im = net.cybercorlin.util.logger.appender.IMAppender 
log4j.appender.im.host = mail.cybercorlin.net 
log4j.appender.im.username = username 
log4j.appender.im.password = password 
log4j.appender.im.recipient = corlin@cybercorlin.net 
log4j.appender.im.layout=org.apache.log4j.PatternLayout 
log4j.appender.im.layout.ConversionPattern =[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n

一个完整的XML例子

<?xml version="1.0" encoding="UTF-8" ?>  
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">  
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">  
  
    <!-- ========================== 自定义输出格式说明================================ -->  
    <!-- %p 输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL -->  
    <!-- #%r 输出自应用启动到输出该log信息耗费的毫秒数  -->  
    <!-- #%c 输出所属的类目,通常就是所在类的全名 -->  
    <!-- #%t 输出产生该日志事件的线程名 -->  
    <!-- #%n 输出一个回车换行符,Windows平台为“\r\n”,Unix平台为“\n” -->  
    <!-- #%d 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyy MMM dd HH:mm:ss,SSS},输出类似:2002年10月18日 22:10:28,921  -->  
    <!-- #%l 输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数。举例:Testlog4.main(TestLog4.java:10)  -->  
    <!-- ========================================================================== -->  
      
    <!-- ========================== 输出方式说明================================ -->  
    <!-- Log4j提供的appender有以下几种:  -->  
    <!-- org.apache.log4j.ConsoleAppender(控制台),  -->  
    <!-- org.apache.log4j.FileAppender(文件),  -->  
    <!-- org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件), -->  
    <!-- org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件),  -->  
    <!-- org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方)   -->  
    <!-- ========================================================================== -->  
    <!-- 输出到日志文件  -->  
    <appender name="filelog_appender"  
        class="org.apache.log4j.RollingFileAppender">  
        <!-- 设置File参数:日志输出文件名 -->  
        <param name="File" value="log/testlog4jxml_all.log" />  
        <!-- 设置是否在重新启动服务时,在原有日志的基础添加新日志 -->  
        <param name="Append" value="true" />  
        <!-- 设置文件大小 -->  
        <param name="MaxFileSize" value="1MB" />  
        <!-- 设置文件备份 -->  
        <param name="MaxBackupIndex" value="10000" />  
        <!-- 设置输出文件项目和格式 -->  
        <layout class="org.apache.log4j.PatternLayout">  
            <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} %-5p (%c:%L)- %m%n" />  
        </layout>  
    </appender>  
  
    <!-- 输出到日志文件 每天一个日志  -->  
    <appender name="filelog_daily" class="org.apache.log4j.DailyRollingFileAppender">     
        <param name="File" value="log/daily.log" />     
        <param name="DatePattern" value="'daily.'yyyy-MM-dd'.log'" />     
        <layout class="org.apache.log4j.PatternLayout">     
            <param name="ConversionPattern" value="[%d{yyyy-MM-dd HH:mm:ss\} %-5p] [%t] (%c:%L) - %m%n" />     
        </layout>     
    </appender>   
  
    <!-- 输出到控制台中 -->  
    <appender name="console" class="org.apache.log4j.ConsoleAppender">  
        <layout class="org.apache.log4j.PatternLayout">  
            <param name="ConversionPattern"  
                value="%d{yyyy-MM-dd HH:mm:ss} %-5p: %m%n" />  
            <!-- "%-5p: [%t] [%c{3}.%M(%L)] | %m%n" -->  
        </layout>  
    </appender>  
  
    <appender name="EMAIL_QQ" class="org.apache.log4j.net.SMTPAppender">  
        <param name="Threshold" value="INFO"/>  
        <param name="BufferSize" value="128" />  
        <param name="SMTPHost" value="smtp.qq.com" />  
        <param name="SMTPUsername" value="" />  
        <param name="SMTPPassword" value="" />  
        <param name="From" value="" />  
        <param name="To" value="" />  
        <param name="Subject" value="测试邮件发送" />  
        <param name="LocationInfo" value="true" />  
        <param name="SMTPDebug" value="true" />  
        <layout class="org.cjj.log4j.extend.PatternLayout_zh">  
            <param name="ConversionPattern" value="[%d{ISO8601}] %-5p %c %m%n"/>  
        </layout>  
    </appender>  
  
<!--- 异步测试,当日志达到缓存区大小时候执行所包的appender -->  
    <appender name="ASYNC_test" class="org.apache.log4j.AsyncAppender">     
     <param name="BufferSize" value="10"/>     
     <appender-ref ref="EMAIL_QQ"/>  
   </appender>  
  
 <!-- 设置包限制输出的通道 -->  
    <category name="com.package.name" additivity="false"><!-- 日志输出级别,起码可以有5个级别,可以扩展自己的级别,邮件发送必须是ERROR级别不好用,所以最后自己扩展一个邮件发送级别 -->  
        <level value="ERROR" />  
        <appender-ref ref="filelog_daily" />  
        <appender-ref ref="daily_appender" />  
        <appender-ref ref="console" />  
        <appender-ref ref="ASYNC_test" />  
    </category>  
</log4j:configuration>  

Web配置log4j,需求增加以下内容到 WEB-INF/web.xml

   webAppRootKey smilecargo.root log4jConfigLocation classpath:log4j.xml log4jRefreshInterval 60000    org.springframework.web.util.Log4jConfigListener

${smilecargo.root}是web工程相对路径

问题

配置时出现如下问题:

log4j:ERROR setFile(null,true) call failed.
java.io.FileNotFoundException: /home/work/log/web.log (No such file or directory)
    at java.io.FileOutputStream.open0(Native Method)
    at java.io.FileOutputStream.open(FileOutputStream.java:270)
    at java.io.FileOutputStream.<init>(FileOutputStream.java:213)
    at java.io.FileOutputStream.<init>(FileOutputStream.java:133)
    at org.apache.log4j.FileAppender.setFile(FileAppender.java:294)
    at org.apache.log4j.FileAppender.activateOptions(FileAppender.java:165)
    at org.apache.log4j.DailyRollingFileAppender.activateOptions(DailyRollingFileAppender.java:223)
    at org.apache.log4j.config.PropertySetter.activate(PropertySetter.java:307)
    at org.apache.log4j.xml.DOMConfigurator.parseAppender(DOMConfigurator.java:295)
    at org.apache.log4j.xml.DOMConfigurator.findAppenderByName(DOMConfigurator.java:176)
    at org.apache.log4j.xml.DOMConfigurator.findAppenderByReference(DOMConfigurator.java:191)
    at org.apache.log4j.xml.DOMConfigurator.parseChildrenOfLoggerElement(DOMConfigurator.java:523)
    at org.apache.log4j.xml.DOMConfigurator.parseCategory(DOMConfigurator.java:436)
    at org.apache.log4j.xml.DOMConfigurator.parse(DOMConfigurator.java:1004)
    at org.apache.log4j.xml.DOMConfigurator.doConfigure(DOMConfigurator.java:872)
    at org.apache.log4j.xml.DOMConfigurator.doConfigure(DOMConfigurator.java:778)
    at org.apache.log4j.helpers.OptionConverter.selectAndConfigure(OptionConverter.java:526)
    at org.apache.log4j.LogManager.<clinit>(LogManager.java:127)
    at org.apache.log4j.Logger.getLogger(Logger.java:104)
    at org.apache.commons.logging.impl.Log4JLogger.getLogger(Log4JLogger.java:262)
    at org.apache.commons.logging.impl.Log4JLogger.<init>(Log4JLogger.java:108)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at org.apache.commons.logging.impl.LogFactoryImpl.createLogFromClass(LogFactoryImpl.java:1025)
    at org.apache.commons.logging.impl.LogFactoryImpl.discoverLogImplementation(LogFactoryImpl.java:844)
    at org.apache.commons.logging.impl.LogFactoryImpl.newInstance(LogFactoryImpl.java:541)
    at org.apache.commons.logging.impl.LogFactoryImpl.getInstance(LogFactoryImpl.java:292)
    at org.apache.commons.logging.impl.LogFactoryImpl.getInstance(LogFactoryImpl.java:269)
    at org.apache.commons.logging.LogFactory.getLog(LogFactory.java:655)
    at org.springframework.util.PropertyPlaceholderHelper.<clinit>(PropertyPlaceholderHelper.java:40)
    at org.springframework.web.util.ServletContextPropertyUtils.<clinit>(ServletContextPropertyUtils.java:38)
    at org.springframework.web.util.Log4jWebConfigurer.initLogging(Log4jWebConfigurer.java:128)
    at org.springframework.web.util.Log4jConfigListener.contextInitialized(Log4jConfigListener.java:49)
    at org.eclipse.jetty.server.handler.ContextHandler.callContextInitialized(ContextHandler.java:890)
    at org.eclipse.jetty.servlet.ServletContextHandler.callContextInitialized(ServletContextHandler.java:532)
    at org.eclipse.jetty.server.handler.ContextHandler.startContext(ContextHandler.java:853)
    at org.eclipse.jetty.servlet.ServletContextHandler.startContext(ServletContextHandler.java:344)
    at org.eclipse.jetty.webapp.WebAppContext.startWebapp(WebAppContext.java:1514)
    at org.eclipse.jetty.maven.plugin.JettyWebAppContext.startWebapp(JettyWebAppContext.java:359)
    at org.eclipse.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1476)
    at org.eclipse.jetty.server.handler.ContextHandler.doStart(ContextHandler.java:785)
    at org.eclipse.jetty.servlet.ServletContextHandler.doStart(ServletContextHandler.java:261)
    at org.eclipse.jetty.webapp.WebAppContext.doStart(WebAppContext.java:545)
    at org.eclipse.jetty.maven.plugin.JettyWebAppContext.doStart(JettyWebAppContext.java:434)
    at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68)
    at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:131)
    at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:113)
    at org.eclipse.jetty.server.handler.AbstractHandler.doStart(AbstractHandler.java:113)
    at org.eclipse.jetty.server.handler.ContextHandlerCollection.doStart(ContextHandlerCollection.java:167)
    at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68)
    at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:131)
    at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:113)
    at org.eclipse.jetty.server.handler.AbstractHandler.doStart(AbstractHandler.java:113)
    at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68)
    at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:131)
    at org.eclipse.jetty.server.Server.start(Server.java:449)
    at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:105)
    at org.eclipse.jetty.server.handler.AbstractHandler.doStart(AbstractHandler.java:113)
    at org.eclipse.jetty.server.Server.doStart(Server.java:416)
    at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68)
    at org.eclipse.jetty.maven.plugin.AbstractJettyMojo.startJetty(AbstractJettyMojo.java:467)
    at org.eclipse.jetty.maven.plugin.AbstractJettyMojo.execute(AbstractJettyMojo.java:333)
    at org.eclipse.jetty.maven.plugin.JettyRunMojo.execute(JettyRunMojo.java:180)
    at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:134)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:207)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:153)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:145)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:116)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:80)
    at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build(SingleThreadedBuilder.java:51)
    at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:128)
    at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:307)
    at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:193)
    at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:106)
    at org.apache.maven.cli.MavenCli.execute(MavenCli.java:863)
    at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:288)
    at org.apache.maven.cli.MavenCli.main(MavenCli.java:199)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:289)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:229)
    at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:415)
    at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:356)
    at org.codehaus.classworlds.Launcher.main(Launcher.java:47)
log4j:ERROR Either File or DatePattern options are not set for appender [file].

解决方案:

这种情况一般是 log 文件的路径不对,要不是文件路劲不存在,要不就是无权限写入。

reference


2017-12-05 log , java

git 不同阶段撤回

因为平时使用 SmartGit 这样一个 Git client,所以也没有太大注意 Git 中不同阶段撤回的方式,虽然平时接触过 git reset--soft--hard 来撤销已提交的 commit,但没有形成一个系统的知识体系。大家都知道 Git 是一个分布式版本控制,所以 Git 会有一个本地库,和一个远端库,而平时提交代码的时候,一般也都是先从本地工作区提交代码

git add .
git commit -s
git push

这几个步骤,虽然平淡无奇,但是展开说,就体现了 Git 的重要的环节,一段代码的提交顺序:

工作区  ->  git add .  -> 暂存区 -> git commit -> 本地仓库 -> git push -> 远程仓库

这里就要提到 Git 中的四个区:

  • 工作区 working
  • 暂存区 stage
  • 本地仓库 local repository
  • 远程仓库 remote repository

被追踪的文件,在未进入和进入上述四个区之后分别有一个状态,所以一共有五个状态:

  • 未修改 origin
  • 已修改 modified
  • 已暂存 staged
  • 已提交 committed
  • 已推送 pushed

在了解这几个基本概念之后,如何检查本地的修改,以及如何查看不同状态之间的修改,这就要用到 git diff 命令。

直接使用 git diff 命令,能够查看已修改,未暂存的内容

使用 git diff --cache 来查看已暂存,未提交的内容

使用 git diff origin/master master 来查看已提交,未推送的差异。

工作区          暂存区           本地仓库                    远程仓库
    \          /     \          /         \                  /
     \        /       \        /           \                /
     git diff         git diff --cache     git diff origin/master master

图解

git-workspace-index

在知道如何查看四个不同区之间的差异后,如何使用 git reset 来撤销呢?

撤销工作区修改

如果只是在编辑器中修改了文件的内容,还未使用 git add 将修改提交到暂存区,那么可以使用 git checkout . 或者 git checkout -- <file> 来丢弃本地全部修改或者丢弃某文件的修改。

可以将 git add .git checkout . 看做一对反义词,修改完成后,如果想 Git 往前进一步,让修改进入暂存区,执行 git add . 如果向后退则执行 git checkout .

撤销暂存区修改

如果已经执行了 git add,意味着暂存区中已经有了修改,但是需要丢弃暂存区的修改,那么可以执行 git reset

对于已经被 Git 追踪的文件,可以使用

git reset <file>

来单独将文件从暂存区中丢弃,将修改放到工作区。

对于从来没有被 Git 追踪过,是 new file 的文件,则需要使用:

git reset HEAD <file>

来将新文件从暂存区中取出放到工作区。

如果确定暂存区中的修改完全不需要,则可以使用

git reset --hard

直接将修改抛弃,谨慎使用 –hard 命令, 暂存区中所有修改都会被丢弃。修改内容也不会被重新放到工作区。

撤销本地提交

对于已经本地的提交,也就是使用 git add 并且执行了 git commit 的修改,这时候本地的修改已经进入了本地仓库,而这是需要撤销这一次提交,或者本地的多次提交,怎么办?

git reset --hard origin/master

同样还是 git reset 命令,但是多了 origin/masterorigin 表示远端仓库的名字,默认为 origin,可能也有其他自己的名字,origin/master 表示远程仓库,既然本地的修改已经不再需要,那么从远端将代码拉回来就行。

不过不建议直接使用 git reset --hard origin/master 这样太强的命令,如果想要撤销本地最近的一次提交,可以使用

git reset --soft HEAD~1

这行命令表示,将最近一次提交 HEAD~1 从本地仓库回退到暂存区,--soft 不会丢弃修改,而是将修改放到暂存区,后续继续修改,或者丢弃暂存区的修改就可以随意了。如果要撤销本地两次修改,则改成 HEAD~2 即可,其他同类。

不过要注意的是,已经提交到远端的提交,不要使用 git reset 来修改,对于多人协作项目会给其他人带来很多不必要的麻烦。

撤销远端仓库修改

对于已经推送的修改,原则上是不要撤销的,不过 Git 给了使用者充分的自由,在明确自己在做什么的情况下,可以使用 git push -f 使用 force 选项来将本地库 force 覆盖远端仓库,强制 push 到远端。

对于个人,一个人使用的项目使用这样的方式,并没有太大问题,但是如果对于多人项目,如果你强行改变了远端仓库,别人再使用的时候就会出现很多问题,所以使用 git push -f 时一定要想清楚自己在做什么事情。


2017-12-04 git , linux

Python 自然语言处理包 nltk 使用

nltk 是 Python 下一个自然语言处理相关的库,可以方便的实现分词,词性标注等等。

安装

pip install nltk

然后在终端执行 python, 进入交互式编辑环境

>> import nltk
>> nltk.download()

下载相关模块

分词

nltk.sent_tokenize(text) #对文本按照句子进行分割

nltk.word_tokenize(sent) #对句子进行分词

词性标注

nltk.pos_tag()

词形还原

from nltk.stem import WordNetLemmatizer
lemmatizer = WordNetLemmatizer()
lemmatizer.lemmatize(word)

reference


2017-12-01 nltk , python , nlp

frp 使用笔记

frp 是中国开发者 fatedier 的作品,frp 是一个高性能的反向代理应用,可以帮助您轻松地进行内网穿透,对外网提供服务,支持 tcp, udp, http, https 等协议类型,并且 web 服务支持根据域名进行路由转发。

frp用法和ngrok相似,但是frp比ngrok更加优秀。 配置过程很简单,但是也遇到一些问题,所以把过程记录下来。

frp 作用

  • 利用处于内网或防火墙后的机器,对外网环境提供 http 或 https 服务。
  • 对于 http, https 服务支持基于域名的虚拟主机,支持自定义域名绑定,使多个域名可以共用一个80端口。
  • 利用处于内网或防火墙后的机器,对外网环境提供 tcp 和 udp 服务,例如在家里通过 ssh 访问处于公司内网环境内的主机。

frp 配置

frps.ini 服务端配置:

[common] 
bind_port = 7000

frpc.ini 客户端配置

[common] 
server_addr = x.x.x.x   # 填写公网服务器IP地址
server_port = 7000 

[ssh-computer-name] 
type = tcp 
local_ip = 127.0.0.1 
local_port = 22 
remote_port = 6000 #配置服务器端口

然后使用 ssh user@x.x.x.x -p 6000 或者 ssh -o Port=6000 user@x.x.x.x 来连接内网的机器。

再配置完之后可以使用 supervisor 来管理,实现进程死掉后自动重启。

reference


2017-11-30 frp , ssh , linux

电子书

Google+

最近文章

  • 由 WebM 格式学习常见的容器和编码格式 因为使用 YouTube 所以接触到了 WebM 格式,这个格式 Google 开源的一个媒体容器格式,常见的文件后缀名是 .webm,他设计的目标是为了给 HTML5 提供视频和音频。Google 发起的 WebM 项目还有一个姊妹项目 WebP 是提供图像编码的。BSD 协议开源。1 https://en.wikipedia.org/wiki/WebM ↩
  • Jupyter 简单使用 Jupyter 是一个为了支持多语言交互式编程的项目, Jupyter Notebook 是一个开源的网络程序,允许用户创建和分享包含代码,视图,方程式,文本的文档。
  • GraphQL 初识 在开发服务端接口的时候接触到 GraphQL 这个名词,故而有了这篇文章。因为初始,所以整理过程难免有些错误和疏漏,请留言告知。在我们面对一个新的名词,或者一门新的技术时,了解的过程可以分成这么几部分,他是什么,他解决了什么问题,他和目前同类型的技术相比优势在哪里,这样几个部分去看也就能够比较粗略,但是快速的了解一样新东西了。所以这篇文章的组织结构也以这样的方式进行。
  • go 语言学习笔记 1 并发 Go 语言在语言级别支持协程,叫 goroutine。Go 语言标准库提供的所有系统调用 (syscall) 操作,当然也包括所有同步 IO 操作,都会出让 CPU 给其他 goroutine
  • 跨平台开源卡片记忆工具 anki 一开始的时候我无法用一句话来形容这个软件,大部分人将他称为背单词软件,部分人有拿他作为知识笔记软件,甚至有人拿他来学习乐谱,诗歌,但总之如果要用简单的话来描述这个软件,那么跨平台必定是关键词,另外一个关键词就是卡片,在另外一个就是循环记忆,那么至于卡片上承载什么样的内容,就完全由用户来决定了。