Hack × StrongSoft

Faith Comes By Hacking

Gradle + Groovy 1.8 + Log4j

| Comments

Groovy 從 1.8 版本開始支援 @Log 標記(Annotation),共有四種:

  • @Log for java.util.logging
  • @Commons for Commons-Logging
  • @Log4j for Log4J
  • @Slf4j for SLF4J

這篇教學以 Apache Log4j 為例,搭配 Gradle 專案建置 Script。

先在 build.gradle 設定 dependencies,加入 groovy 1.8 及 log4j 1.2 的設定。

1
2
3
4
5
6
7
apply plugin: 'java'
apply plugin: 'groovy'

dependencies {
  groovy 'org.codehaus.groovy:groovy-all:1.8.3'
  runtime 'log4j:log4j:1.2.16'
}

在 class 上方加入 @Log4j, 這個 Annotation 由 groovy.util.logging package 提供。 在程式碼需要除錯訊息的地方加入 Log 輸出。

路徑: src/main/groovy/SimpleClass.groovy

1
2
3
4
5
6
7
8
import groovy.util.logging.*

@Log4j
class SimpleClass {
  def log2test {
    log.debug 'message send to logger'
  }
}

依照訊息的層級,可以呼叫其他不同方法:

  • log.info
  • log.debug
  • log.warning
  • log.error

接下來要定義一個 log4j.properties 設定檔。

路徑: src/main/resources/log4j.properties

1
2
3
4
5
6
7
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=stacktrace.log
log4j.appender.file.encoding=utf-8
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

log4j.rootLogger=debug, file

這一組設定會將 Log 寫入 stacktrace.log 記錄檔, 並且採用 UTF-8 編碼(支援中文訊息)。

解決 Gradle Dependency 處理速度慢的問題

| Comments

Gradle 的 dependencies 可以設定 Maven Repository 的套件, 讓 Gradle 自動下載相依的 Jar 檔案。 例如 HttpBuilder 的設定範例(build.gradle):

1
2
3
4
dependencies {
    groovy 'org.codehaus.groovy:groovy-all:1.8.3'
    compile 'org.codehaus.groovy.modules.http-builder:http-builder:0.5.1'
}

但有時候加入了某些相依套件, 會讓建置程序變得超級慢, 因此在 gradle task 執行時, 會卡在「Resolve dependencies」這個訊息很久。

1
> Building > :compileGroovy > Resolve dependencies ':compile'

利用以下的指令,可以檢查目前專案依賴的套件共有哪些。

1
gradle dependencies

執行後將會看到這個輸出結果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
compile - Classpath for compiling the main sources.
+--- org.codehaus.groovy:groovy-all:1.8.3 [default]
\--- org.codehaus.groovy.modules.http-builder:http-builder:0.5.1 [default]
     +--- org.apache.httpcomponents:httpclient:4.0.3 [master,compile,runtime]
     |    +--- org.apache.httpcomponents:httpcore:4.0.1 [master,compile,runtime]
     |    +--- commons-logging:commons-logging:1.1.1 [master,compile,runtime]
     |    \--- commons-codec:commons-codec:1.3 [master,compile,runtime]
     +--- net.sf.json-lib:json-lib:2.3 [master,compile,runtime]
     |    +--- commons-logging:commons-logging:1.1.1 [master,compile,runtime] (*)
     |    +--- commons-beanutils:commons-beanutils:1.8.0 [master,compile,runtime]
     |    |    \--- commons-logging:commons-logging:1.1.1 [master,compile,runtime] (*)
     |    +--- commons-collections:commons-collections:3.2.1 [master,compile,runtime]
     |    +--- commons-lang:commons-lang:2.4 [master,compile,runtime]
     |    \--- net.sf.ezmorph:ezmorph:1.0.6 [master,compile,runtime]
     |         \--- commons-lang:commons-lang:2.4 [master,compile,runtime] (*)
     +--- org.codehaus.groovy:groovy:1.7.10 [master,compile,runtime]
     |    +--- antlr:antlr:2.7.7 [master,compile,runtime]
     |    +--- asm:asm:3.2 [master,compile,runtime]
     |    +--- asm:asm-commons:3.2 [master,compile,runtime]
     |    |    \--- asm:asm-tree:3.2 [master,compile,runtime]
     |    |         \--- asm:asm:3.2 [master,compile,runtime] (*)
     |    +--- asm:asm-util:3.2 [master,compile,runtime]
     |    |    \--- asm:asm-tree:3.2 [master,compile,runtime] (*)
     |    +--- asm:asm-analysis:3.2 [master,compile,runtime]
     |    |    \--- asm:asm-tree:3.2 [master,compile,runtime] (*)
     |    \--- asm:asm-tree:3.2 [master,compile,runtime] (*)
     +--- net.sourceforge.nekohtml:nekohtml:1.9.9 [master,compile,runtime]
     |    \--- xerces:xercesImpl:2.8.1 [master,compile,runtime]
     |         \--- xml-apis:xml-apis:1.3.03 [master,compile,runtime]
     \--- xml-resolver:xml-resolver:1.2 [master,compile,runtime]

從樹狀圖可以發現, http-builder 依賴的套件中, groovy:1.7.10 是多餘且冗長的部份。 我們已經在另一行指定 groovy-all:1.8.3 這個版本, 因此可以利用 exclude 設定將 groovy:1.7.10 排除。

1
2
3
4
5
6
dependencies {
    groovy 'org.codehaus.groovy:groovy-all:1.8.3'
    compile ('org.codehaus.groovy.modules.http-builder:http-builder:0.5.1')  {
        exclude group: 'org.codehaus.groovy', modules: 'groovy'
    }
}

再重新執行一次 gradle dependencies, 可以發現樹狀圖變得比較精簡, 而 gradle 執行過程也會加快許多, 不會在 Resolve dependencies 時卡住。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
+--- org.codehaus.groovy:groovy-all:1.8.3 [default]
\--- org.codehaus.groovy.modules.http-builder:http-builder:0.5.1 [default]
     +--- org.apache.httpcomponents:httpclient:4.0.3 [master,compile,runtime]
     |    +--- org.apache.httpcomponents:httpcore:4.0.1 [master,compile,runtime]
     |    +--- commons-logging:commons-logging:1.1.1 [master,compile,runtime]
     |    \--- commons-codec:commons-codec:1.3 [master,compile,runtime]
     +--- net.sf.json-lib:json-lib:2.3 [master,compile,runtime]
     |    +--- commons-logging:commons-logging:1.1.1 [master,compile,runtime] (*)
     |    +--- commons-beanutils:commons-beanutils:1.8.0 [master,compile,runtime]
     |    |    \--- commons-logging:commons-logging:1.1.1 [master,compile,runtime] (*)
     |    +--- commons-collections:commons-collections:3.2.1 [master,compile,runtime]
     |    +--- commons-lang:commons-lang:2.4 [master,compile,runtime]
     |    \--- net.sf.ezmorph:ezmorph:1.0.6 [master,compile,runtime]
     |         \--- commons-lang:commons-lang:2.4 [master,compile,runtime] (*)
     +--- net.sourceforge.nekohtml:nekohtml:1.9.9 [master,compile,runtime]
     |    \--- xerces:xercesImpl:2.8.1 [master,compile,runtime]
     |         \--- xml-apis:xml-apis:1.3.03 [master,compile,runtime]
     \--- xml-resolver:xml-resolver:1.2 [master,compile,runtime]

讓 Octopress 支援更多語言的程式碼區塊(更新 Pygments)

| Comments

如果在 Octopress 的文章中,程式碼區塊用了不支援的程式語言,例如 Groovy:

1
2
3
 ``` groovy
 println 'hello'
 ```

執行 rake generate 就會爆炸!

/Users/user1/.rvm/gems/ruby-1.9.2-p290/gems/rubypython-0.5.1/lib/rubypython/rubypyproxy.rb:198:in `method_missing’: ClassNotFound: no lexer for alias ‘groovy’ found (RubyPython::PythonError)

因為 Octopress 的程式碼區塊 Syntax Highlight, 是使用 pygments.rb 這個套件; 而 pygments.rb 會再去呼叫 Python 的 Pygments, 因此災難的源頭就是 Pygments 不支援區塊指定的程式語言。

但如果從 Pygments 的 Supported languages 清單, 卻又可能發現清單中明明有列出該語言名稱。 這時候必須到 Available lexers 查詢, 如果在程式語言的說明有一行 New in Pygments 1.5. , 就表示只要將 Pygments 更新到 1.5 版, 即可支援該程式語言(目前 Pygments 的穩定版為 1.4)。

更新的步驟如下:

先切換到 pygments.rb 資料夾

1
cd .rvm/gems/ruby-1.9.2-p290/gems/pygments.rb-0.1.3/vendor

用 hg 下載一份最新版 Pygments

1
hg clone https://bitbucket.org/birkenfeld/pygments-main

再將 Pygments-1.4 的資料夾掉包

1
2
mv Pygments-1.4 Pygments-1.4-old
mv pygments-main Pygments-1.4

回到 Octopress Blog 重新執行 rake generate,應該就不會爆炸了。

MarkdownJ 使用範例(Groovy + Grab)

| Comments

Markdown 是一種易讀易寫的輕量文字格式。

要將 Markdown 轉換成其他格式,除了命令列的 Pandoc 工具外, Java / Groovy 程式可以利用 MarkdownJ 這個函式庫。

在這個 頁面 可以找到 MarkdownJ 的 Maven Repository 來源, 因此加入一行 Groovy 的 Grab 設定:

1
2
@GrabResolver(name='scala-tools', root='http://scala-tools.org/repo-releases')
@Grab('org.markdownj:markdownj:0.3.0-1.0.2b4')

接著就可以引用 MarkdownProcessor 類別。

1
import com.petebevin.markdown.MarkdownProcessor

使用 MarkdownProcessor 的 markdown 方法,可以將一段 Markdown 格式的字串轉換成 HTML 代碼。

1
2
3
4
5
6
7
8
9
10
def m = new MarkdownProcessor()

println m.markdown('''
Heading
=======

* item1
* item2
* item3
''')

範例程式碼可以從 Gist 取得。

Hello, Octopress

| Comments

這個網站使用 Octopress 架設, 並使用免費的 GitHub Pages 網頁空間。

第一次使用 Octopress,就發現「回不去了」!

看到 Octopress 讓我覺得很驚豔, 用 Markdown 語法很快寫好一篇網誌, 接著用 rake 就能 generate 並 deploy 到 GitHub , 就像在 Coding 一樣快樂無比, 很有親切感。

每位想寫網誌的 hacker 或 geek,一定要試試 Octopress : )

延伸閱讀