Angular 最佳实践
- 控制器和
Provider
(Service,Factory)用于修改数据模型,而不是HTML - HTML和指令定义布局,以及到模型的绑定
- 如果要在控制器之间共享数据,那么创建一个服务或工厂 - 它们是能在整个应用程序生命周期内共享的单件对象
- 如果你需要一个HTML Widget, 应该创建一个指令
- 如果你有一些数据,并且需要更新HTML,NO! NO! NO!, 更新模型就可以了,保证HTML绑定到模型就可以了.
TODO::后续有发现继续增加
Provider
(Service,Factory)用于修改数据模型,而不是HTMLTODO::后续有发现继续增加
本文翻译自如下文章, 因为不是文学作品而是技术文章,因此不遵照
信达雅
的原则,让人容易理解即可, 没有逐句翻译原文的语言含义,而是根据其含义用更符合汉语的语言习惯来表达.
http://www.bennadel.com/blog/2632-creating-asynchronous-alerts-prompts-and-confirms-in-angularjs.htm
有过在前端编程经验的人都知道,调用alert()
, prompt()
, 和confirm()
会阻塞浏览器执行后续的Javascript代码,直到用户做出反应. 这个问题会让前端开发变得比较棘手.
比如,一个常见的问题是当alert()
这类阻塞操作促发的时候,假设浏览器后台每隔N秒会向服务器请求更新数据,那么后台的Ajax更新也会被阻塞, 通常解决此类问题的方式转换到使用模态对话框.这种转换并不容易.因此促使原作者创建alert()
,prompt()
和confirm()
的promise
异步处理模式的非阻塞版本.
理解本文的关键是要理解
promise
异步处理模式, 关于什么是promise
异步处理模式,这里不做解释,请自行Google/百度
本文的项目地址为: http://bennadel.github.io/JavaScript-Demos/demos/creating-asynchronous-prompts-angularjs/
https://auth0.com/blog/2014/01/07/angularjs-authentication-with-cookies-vs-token/
实现服务器认证有两种基本的方法:
基于Cookie的认证
(你可以在这里找到例子), 每次请求时,其采用服务器端Cookie
认证用户基于Token的认证
. 依赖于一个每次请求时向服务器发送一个签名的Token.有时候跨域请求RESTFUL API做测试目的,使用cors
模块又比较麻烦,下面的几行代码使用request
模块作为Express的中间件实现Web代理的功能,简单,小巧.
下面的子目录可以放到应用程序的根目录:
node_modules
任何你想要同应用程序一起打包的Node.js模块都可以放在这里plugins
NPAPI插件文件不需要打包 nwsnapshot
文件
警告:
do not assume your node_modules
that target one platform work as is in all platforms. For instance node-email-templates
has specific Windows & Mac os x npm install
commands. Besides, it requires python to install properly, which is not installed by default on Windows.
As a rule of thumb npm install your package.json on each platform you target to ensure everything works as expected.
Every app package should contain a manifest file named package.json
, it will tell node-webkit
how to open the app and control how the browser behaves.
静态站点流行度排名
http://staticsitegenerators.net/
Static web site with Markdown (GitHub pages actually) / Jekyll alternatives
http://stackoverflow.com/questions/16504449/static-web-site-with-markdown-github-pages-actually-jekyll-alternatives
开源静态站生成器列表
http://www.staticgen.com/
http://blog.bmannconsulting.com/node-static-site-generators
docpad
http://docpad.org
Hexo
https://github.com/tommy351/hexo
generator-pencil
http://www.html-js.com/topic/722
Heckle
https://github.com/marijnh/heckle
http://thechangelog.com/heckle-the-jekyll-clone-in-node-js/
Wintersmith
http://wintersmith.io/
Jekyll
http://jekyllrb.com/
Octopress
http://octopress.org/
Nanoc
http://nanoc.ws/
Chromium 在chrome://gpu
页面提供GPU相关的诊断信息,但在node-webkit
中这个页面是坏的. 但是可以通过devtools
获取.
Clipboard API 需要 node-webkit >= v0.3.0
的支持
Clipboard
是一个剪切板(Windows,GTK)和粘贴板(Mac)的抽象,当前它仅支持在系统剪切板中读写纯文本.
简单Angular.js应用程序的预载动画provider
ngActivityIndicator 是一个小巧的,一体化方案,可定制皮肤,仅依赖 Angular.js
可以手动下载需要的ngActivityIndicator文件,或者通过bower
前端包管理器来安装:
1 | bower install ngActivityIndicator |
原文: http://blog.sethladd.com/2014/02/angular-and-polymer-data-binding.html
Angular 是一个非常强大的MVVM框架, Polymer 是一个基于Web组件的对自定义元素的增强库,如何让他们和谐地共存于同一个应用. 本文将介绍通过数据绑定如何连接Angular组件和Polymer元素.
https://www.npmjs.org/package/grunt-peon-gui
grunt-peon-gui
是一个grunt插件,基于Web,运行grunt-peon-gui
的时候会自动启动一个监听在8080
端口的Node.js
Web服务器,并自动打开浏览器显示当前项
1 | npm install grunt-peon-gui --save-dev |
本文收集关于在Node.js
项目中通过模型定义自动生成API接口文档的工具和方法
本文说明如何使用Google的PageSpeed Insights服务,node.js的PSI模块,以及自动build工具Grunt,Gulp把Web性能测试融入到项目构建过程中, 并生成性能分析报告.
1 | npm install --save psi |
1 | var psi = require('psi'); psi({ // key: '...', optional url: 'http://html5rocks.com', paths: '', // optional locale: 'en_GB', // optional strategy: 'mobile', // optional threshold: 80 // optional }); |
2012-07-29更新,
win32reg
现在只支持REG_SZ
不支持REG_EXPAND_SZ
,没有测试REG_SZ
类型的数据,在环境变量中包含%VAR%
形式的变量是否能够正常工作读取保存在文件中的环境变量,并同步到注册表:
env.erl
1 | %% Created: 2011-5-26 %% Description: TODO: Add description to env %% -module(env). %% There are six entry points in the Windows registry, %% top level keys. They can be abbreviated in the win32reg module as: %% Abbrev. Registry key %% ======= ============ %% hkcr HKEY_CLASSES_ROOT %% current_user HKEY_CURRENT_USER %% hkcu HKEY_CURRENT_USER %% local_machine HKEY_LOCAL_MACHINE %% hklm HKEY_LOCAL_MACHINE %% users HKEY_USERS %% hku HKEY_USERS %% current_config HKEY_CURRENT_CONFIG %% hkcc HKEY_CURRENT_CONFIG %% dyn_data HKEY_DYN_DATA %% hkdd HKEY_DYN_DATA % 顶级路径必须小写 -define(CURRENT_USER, "\\hkey_current_user\\Environment"). -define(CURRENT_USER_TEST, "\\hkey_current_user\\EnvironmentTest"). %% %% Exported Functions %% -export([environments/0]). %% %% Local Functions %% environments() -> % 以读写模式打开注册表 {ok, Reg} = win32reg:open([write]), % 设置当前Key case win32reg:change_key(Reg, ?CURRENT_USER) of ok -> % Change key, 如果不存在就创建 win32reg:change_key_create(Reg, ?CURRENT_USER_TEST), % 从文件中读取Tuples {ok, Envs} = file:consult("./win32reg/env.config"), % 逐条创建注册表Item Result = lists:foreach(fun({Key, Value}) -> win32reg:set_value(Reg, Key, Value) end, Envs), % 关闭注册表 win32reg:close(Reg), % 返回值 Result; _ -> false end. |
保存在文件中的环境变量, 以Erlang Term的格式:
env.config
1 | {"ANDROID","D:\\usr\\android-sdk-windows\\platform-tools"}. {"ANT_HOME","D:\\usr\\apache-ant-1.8.0"}. {"ARCHDIR","windows"}. {"CAKE","D:\\chaw\\cakephp\\cake\\console"}. {"CEAN_SERVER","http://cean.process-one.net"}. {"ERLANG_HOME","D:\\usr\\erl5.9.1"}. {"ffmpeg","D:\\usr\\ffmpeg-git-9d4cb45-32-bit-shared\\bin"}. {"GETTEXT_TOOLS","D:\\usr\\gettext-tools-0.13.1.bin.woe32"}. {"GIT","D:\\usr\\Git\\bin"}. {"Haskell","D:\\usr\\Haskell\\2011.2.0.1"}. {"HOME","C:\\Documents and Settings\\Administrator"}. {"HTMLHELP","D:\\Program Files\\HTML Help Workshop"}. {"JAVA_HOME","D:\\Program Files\\Java\\jdk1.6.0_24"}. {"LUA_HOME","D:\\usr\\lua\\Lua\\5.1"}. {"M2_HOME","D:\\usr\\apache-maven-3.0.3"}. {"MAVEN_OPTS","-Xms256m -Xmx512m"}. {"MongoDB","D:\\usr\\MongoDb\\mongodb-win32-i386-1.8.1\\bin"}. {"MYSQL","D:\\usr\\mariadb-5.2.6-win32\\bin"}. {"NODE_PATH","C:\\Documents and Settings\\Administrator\\Application Data\\npm\\node_modules;"}. {"PANDOC","D:\\Program Files\\Pandoc\\bin"}. {"PHP_HOME","D:\\usr\\php"}. {"PROTO_BUFFER","D:\\usr\\protoc-2.4.1-win32"}. {"PYJAMAS_HOME","G:\\pyjamas-0.8.1~+alpha1"}. {"PYTHON_HOME","D:\\usr\\python26"}. {"RabbitMQ","D:\\usr\\RabbitMQ Server\\rabbitmq_server-2.4.1\\sbin"}. {"RABBITMQ_CONSOLE_LOG","new"}. {"SVN","D:\\usr\\svn-win32-1.6.6\\bin"}. {"TITANIUM_HOME","C:\\Documents and Settings\\Administrator\\Application Data\\Titanium\\mobilesdk\\win32\\1.7.2"}. |
Windows的环境变量修改起来很坑,那个对话框不能最大化,看不到完整的东西.有时候变量路径又很长.
1 | %% Created: 2011-5-26 %% Description: TODO: Add description to env -module(env). -define(CURRENT_USER, "\\hkey_current_user\\environment"). %% %% Include files %% %% %% Exported Functions %% -export([environments/0]). %% %% API Functions %% %% %% Local Functions %% environments() -> % 打开注册表 {ok, Reg} = win32reg:open([read]), % 设置当前Key case win32reg:change_key(Reg, ?CURRENT_USER) of ok -> % 读取当前Key下的所有值 {ok, KVs} = win32reg:values(Reg), % 打开文件 {ok, S} = file:open("data1.dat", write), lists:foreach(fun({KK,VV}) -> io:format(S, "~p = ~p~n",[KK, VV]) % 写入 end, KVs), % 关闭注册表 win32reg:close(Reg), % 关闭文件 file:close(S); _ -> false end. |
Changlogs
2011-06-20 添加测试报告, 在另一台服务器上测试,1W并发,首页index.php无Cache,512M内存的VPS能达到这个程度也算不错.并发几千还是能承载的.就是没几个人来访问,哎^_*!
1 | [root@localhost webbench-1.5]# ./webbench -c 10000 -t 30 http://www.hezhiqiang.info/index.php Webbench - Simple Web Benchmark 1.5 Copyright (c) Radim Kolar 1997-2004, GPL Open Source Software. Benchmarking: GET http://www.hezhiqiang.info/index.php 10000 clients, running 30 sec. Speed=21030 pages/min, 3073918 bytes/sec. Requests: 8441 susceed, 2074 failed. |
Varnish 有内置的负载均衡支持. 如果有多个源服务器,使用起来非常简易.通过声明多个后端服务器启动Varnish,同时设置后端服务器的probe属性来监控后端服务器的健康状况.
1 | /* 如果VCL定义文件内容太多可以分离到单独的文件,并包含进来 */ #include "backends.vcl"; #include "ban.vcl"; backend default { .host = "127.0.0.1"; .port = "8080"; /* Varnish 到后端服务器的连接超时, */ .connect_timeout = 1s; /* 和后端服务器建立连接后,即进入等待接收响应状态,如果响应的第一个字节在5s内没有到达,被认为超时*/ .first_byte_timeout = 5s; /* 第一个字节到达后, 如果后续字节在2s内没有到达,被认为是超时 */ .between_bytes_timeout = 2s; .probe = { .url = "/"; .interval = 5s; .timeout = 1 s; .window = 5; .threshold = 3; } } backend default8081 { .host = "127.0.0.1"; .port = "8081"; .connect_timeout = 1s; .first_byte_timeout = 5s; .between_bytes_timeout = 2s; .probe = { .url = "/"; .interval = 5s; .timeout = 1 s; .window = 5; .threshold = 3; } } |
有了两个后端服务器定义, default 和 default8081 . probe对象指出,Varnish应该每隔5秒去获取一次 / 的内容.如果超过一秒还没有得到内容,被认为是失败.如果五次获取有三次成功,那么认为后端服务器状态被认为是健康. 健康状态检查的详细信息请查看 backend health polling
probe 在Varnish源码中定义为一个C Struct:
1 | struct vrt_backend_probe { const char *url; const char *request; double timeout; double interval; unsigned exp_status; unsigned window; unsigned threshold; unsigned initial; }; |
Director 是一个或多个后端服务器的逻辑组, 在启用健康检查的情况下,当有后端服务器不可用时, 它会自动切换到另一个后端服务器上去. 这在需要系统宕机维护, 同时又不能中断服务的情况下是非常有用的, 比如,凌晨2:00,系统维护,可以关闭一台后端服务器,维护完成后再启动,接着维护下一台,以此类推.
现在这两个后端需要被包含在一个逻辑的 director 中.被作为一个虚拟的后端,称之为 hezhiqiang:
1 | directory hezhiqiang round-robin { {.backend = default;} {.backend = default8081;} } |
关键字 round-robin 指出,请求会以轮询的方式分布到后端服务器.当前(varnish 3.0)还支持另外的director, 包括 simple, hash, random, dns, client.
这些支持的后端负载均衡方式可以在源代码 cache_backend_cfg.c 文件中看到.
1 | void VRT_init_dir(struct cli *cli, struct director **dir, const char *name, int idx, const void *priv) { ASSERT_CLI(); if (!strcmp(name, "simple")) VRT_init_dir_simple(cli, dir, idx, priv); else if (!strcmp(name, "hash")) VRT_init_dir_hash(cli, dir, idx, priv); else if (!strcmp(name, "random")) VRT_init_dir_random(cli, dir, idx, priv); else if (!strcmp(name, "dns")) VRT_init_dir_dns(cli, dir, idx, priv); else if (!strcmp(name, "round-robin")) VRT_init_dir_round_robin(cli, dir, idx, priv); else if (!strcmp(name, "client")) VRT_init_dir_client(cli, dir, idx, priv); else INCOMPL(); } |
现在可以把特定的请求定向到后端服务器了. 在 vcl_recv , 如下:
1 | sub vcl_recv { # 把后端服务器指向上面定义的 directory set req.backend = hezhiqiang; } |
Client director 在 Vanish 2.1.3以及之后版本可用.
如果基于客户端提供的信息做负载均衡,比如IP地址, HTTP 头, 或则请求URL, 那么就可以使用client director
1 | sub vcl_recv { /* Set which backend will be used */ set req.backend = hezhiqiang; /* Load balance by user agent */ set client.identity = req.url; /* Load balance by user agent */ #set client.identity = client.ip; /* Load balance by user agent */ #set client.identity = req.http.user-agent; } |
指定384个后端服务器,其中全部在80端口监听, 0.4秒超时.
1 | director directorname dns { .list = { .host_header = "www.example.com"; .port = "80"; .connect_timeout = 0.4; /* 使用掩码标识的网段作为后端 */ "192.168.15.0"/24; "192.168.16.128"/25; } /* 指定DNS查询的缓存时间 */ .ttl = 5m; /* 追加到客户端提供的主机头后面 */ .suffix = "internal.example.net"; } |
采用round-robin双Nginx后端.搭建在Linode的Plan512 VPS节点上,同时采用XCache作为PHP的加速器,Percona MySQL 服务器.
1 | /*import std;*/ backend default { .host = "127.0.0.1"; .port = "8080"; /* Varnish 到后端服务器的连接超时, */ .connect_timeout = 1s; /* 和后端服务器建立连接后,即进入等待接收响应状态,如果响应的第一个字节在5s内没有到达,被认为超时*/ .first_byte_timeout = 5s; /* 第一个字节到达后, 如果后续字节在2s内没有到达,被认为是超时 */ .between_bytes_timeout = 2s; .probe = { /* 健康检查的目标URL */ .url = "/index.html"; /* 每次检查间隔 */ .interval = 5s; /* 超时 */ .timeout = 1 s; /* 检查次数 */ .window = 5; /* 成功次数 */ .threshold = 3; } } backend default8081 { .host = "127.0.0.1"; .port = "8081"; .connect_timeout = 1s; .first_byte_timeout = 5s; .between_bytes_timeout = 2s; .probe = { .url = "/"; .interval = 5s; .timeout = 1 s; .window = 5; .threshold = 3; } } director hezhiqiang round-robin { {.backend = default;} {.backend = default8081;} } sub vcl_recv { set req.backend = hezhiqiang; # Load balance by url set client.identity = req.url; # Load balance by client ip #set client.identity = client.ip; # Load balance by user agent #set client.identity = req.http.user-agent; # std.log("fishy is going on with the vhost" + req.http.host); if (req.request == "GET" && req.url ~ "\.(gif|jpg|png|swf|css|js)$") { unset req.http.Cookie; } # do not cache the /tag, /textpattern, and /category if ( req.url ~ "^/tag/" ) { return (pass); } if ( req.url ~ "^/textpattern/") { return (pass); } if ( req.url ~ "^/category/" ) { return (pass); } if ( req.url ~ "^/html/") { return (pass); } } sub vcl_deliver { # add debugging headers, so we can see what's cached set resp.http.X-Served-By = server.hostname; if (obj.hits > 0) { set resp.http.X-Cache = "HIT"; set resp.http.X-Cache-Hits = obj.hits; } else { set resp.http.X-Cache = "MISS"; } # remove some headers added by varnish # unset resp.http.Via; # unset resp.http.X-Varnish; } |
2011-05-31 创建
2014-09-29 更新
$HOME/.erlang.cookie
erl -setcookie AFRTY12ESS3412735ASDF12378
erlang:set_cookie(node(),C)
1 | -module(kvs). %% Include files %% Exported Functions -export([start/0, store/2, lookup/1]). %% API Functions start() -> io:format("starting server...~n"), % 启动kvs服务,派生一个新进程,进入循环 register(kvs, spawn(fun()-> loop() end)). store(Key, Value) -> io:format("store~n"), rpc({store, Key, Value}). lookup(Key) -> io:format("call lookup~n"), rpc({lookup, Key}). % Local Functions % 消息代理函数 rpc(Q) -> io:format("rpc~n"), % 向进程kvs发送消息 {self(), Q},其中self()表示当前进程Pid, Q为参数 kvs ! {self(), Q}, receive {kvs, Reply} -> Reply end. loop() -> io:format("entering loop...~n"), receive {From, {store, Key, Value}} -> io:format("value ~p with ~p stored~n", [Value, Key]), put(Key, {ok,Value}), From ! {kvs, true}, loop(); {From, {lookup, Key}} -> io:format("get the value of key: ~p~n", [Key]), From ! {kvs, get(Key)}, loop() end |
1 | erl -sname server erl -sname client |
1 | erl -name server erl -name client |
-name
需要使用到DNS服务,而-sname
不需要使用DNS,可用于本机测试,局域网也可以使用-sname
启动Erlang系统.
启动服务器, 派生一个新进程,立即进入循环
1 | (server@localhost) > kvs:start(). starting server... entering loop... true |
1 | (client@localhost) > rpc:call('server@localhost',kvs,store,[google, "http://www.google.com"]). |
1 | (server@localhost) > value "http://www.google.com" with google stored (server@localhost) > loop |
1 | (client@localhost) > rpc:call('server@localhost',kvs,lookup,[google]). call lookup rpc {ok,"http://www.google.com"} |
1 | (server@localhost) > get the value of key: google (server@localhost) > loop |
1 | (server@localhost)2> kvs:lookup(google). call lookup rpc get the value of key: google loop {ok,"http://www.google.com"} |
1 | Eshell V5.8 (abort with ^G) % 最长单个匹配 regexp:match("linux,windows,erlang,php,mysql", "[a-z]+"). {match,7,7} |
1 | % 首个匹配 regexp:first_match("linux,erlang,mysql,mnesia", "[a-z]+"). {match,1,5} |
1 | % 匹配,并获取linux子串 1> {M,L} = regexp:matches("linux,erlang,mysql,mnesia", "[a-z]+"), 1> {Start, Length} = lists:nth(1, L), 1> Substring = string:substr("linux,erlang,mysql,mnesia",Start,Length), 1> io:format("The first substring is ~p~n", [Substring]). The first substring is "linux" ok |
1 | % 替换 regexp:sub("webmaster@gmail.com", "@[a-z\.]+", "@163.com"). {ok,"webmaster@163.com",1} |
1 | % 全局替换 regexp:gsub("webmaster@gmail.com,admin@gmail.com", "@[a-z\.]+", "@163.com"). {ok,"webmaster@163.com,admin@163.com",2} |
1 | % 切分 regexp:split("webmaster@gmail.com admin@gmail.com", "\s"). {ok,["webmaster@gmail.com","admin@gmail.com"]} |
1 | % 解析(编译)一次正则表达式,使之能够到处重用,类似Python的re.compile 7> RE = regexp:parse("[a-z]+"). {ok,{pclosure,{char_class,[{97,122}]}}} |
更新历史:
https://bitbucket.org/basho/rebar/wiki/GettingStarted这篇文章是直接下载二进制的rabar,建议从源代码进行编译,可以了解rebar的更多信息.还有现成的rebar.config配置文件,下载编译过程很简单,请看图一
1 | debian:~/erlang# hg clone https://bitbucket.org/basho/rebar debian:~/erlang# cd rebar debian:~/erlang# ./bootstrap |
在src/myapp_app.erl文件的-export()指令后面添加如下行:
1 | -ifdef(TEST). -include_lib("eunit/include/eunit.hrl"). -endif. |
在文件的末尾添加如下行:
1 | -ifdef(TEST). simple_test() -> ok = application:start(myapp), ?assertNot(undefined == whereis(myapp_sup)). -endif. |
1 | debian:~/erlang/rebar/myapp# ./rebat compile eunit |
输出
1 | debian:~/erlang/rebar/myapp# ./rebar compile eunit ==> myapp (compile) ==> myapp (eunit) Test passed. Cover analysis: /var/root/erlang/rebar/myapp/.eunit/index.html |
.eunit
目录中包含了一些调试信息.
在rebar.config中添加如下行,让rebar为我们生成代码覆盖率信息.
1 | {cover_enabled, true}. |
执行:
1 | debian:~/erlang/rebar/myapp# ./rebar clean debian:~/erlang/rebar/myapp# ./rebar compile eunit ==> myapp (compile) ==> myapp (eunit) Test passed. Cover analysis: /var/root/erlang/rebar/myapp/.eunit/index.html |
覆盖率报告html文件生成了.
Rebar提供了开发过程中大多数功能, 包括:
In addition, it allows for OTP embedded system generation, taking advantage of the template processing afforded by rebar and the reltool application.
The most common commands are:
COMMAND | DESCRIPTION |
---|---|
compile | Compile all the available source in the project. |
eunit | Perform unit testing using the Eunit application |
doc | Generate documention using the Edoc application |
clean | Remove any generated artifacts from compilation, unit testing, etc. |
参考:
更新历史:
你可以从 -Google code 或者- Github上获取Log4erl的源代码, Google code上的代码已经旧了,建议从Github上clone 代码
1 | git clone git://github.com/ahmednawras/log4erl.git log4erl |
如图4, 进入Log4erl源代码目录src执行:
1 | make:all([{outdir, "../ebin"}]). |
你要让Erlang能够找到Log4erl,两种方式
1 | erl -pz /path/to/log4erl |
1 | application:start(log4erl). |
创建配置文件并调用log4erl:conf(file)初始化
1 | log4erl:conf("priv/log4erl.conf"). |
同样你可以用编程的方式对Log4erl进行配置
1 | log4erl:add_logger(messages_log). log4erl:add_console_appender(messages_log, cmd_logs, {warn, "[%L] %l%n"}). |
好了,现在可以使用它了.
1 | log4erl:info("Information message"). |
1 | logger [<name>] { ... } |
<name>
指定了Logger的名称,你可以去任意你喜欢的名字.如果不指定任何名字,那么log4erl将把它作为默认的Logger使用,例如:
1 | %% default logger logger { ... } |
在一个Logger中,可以有一到多个Appender,例如
1 | %% Default logger %% it includes a file appender and a console appender logger{ file_appender app2{ dir = ".", level = info, file = my_app, type = size, max = 100000, suffix = log, rotation = 5, format = '[%L] %I %l%n' } console_appender app1{ level = warn, format = '%T %j [%L] %l%n' } } |
Appender的配置格式如下
1 | <appender_type> <name> { ... } |
在Appender中你可以用’property=value’的格式来设置Appender的属性,属性剑以’,’逗号分隔.每种Appender有不同的属性集合.
公共属性:
1 | level = <Level> => 日志级别 (例如: warn) format = <F> => 输出格式 (查看 'Appenders.txt') |
file_appender
1 | dir => 输出路径 (例如: /var/log/my_app) file => 日志文件名称 (例如: my_app_log) type => size,time. 当前仅实现了基于size的日志滚动 max => 每次日志滚动的最大文件大小 suffix => 日志文件后缀 (例如: log) rotation => 循环滚动次数,例如为5, 当滚动到第五个日志文件并且日志文件达到指定size的时候就会覆盖前面的日志文件,依次循环 |
smtp_appender
1 | ip => SMTP服务器IP地址 port => SMTP服务器端口 no_auth username => 用户名 password => 密码 from => 寄信人地址 to => 收信人地址 tilte => 邮件标题 msg => 邮件内容 |
syslog_appender
1 | facility => Facility (例如: ftp) host => 发送syslog消息的目标主机 [可选] port => syslog 端口[可选] |
本文源码:
https://github.com/developerworks/skypebot/tree/master/src/erlang/log4erl_example
参考资料: