29 Dec 2014, 12:03

Emacs で ログ解析をするための便利機能まとめ

はじめに

前回の記事のつづき.

Java 開発で, log4j のログをみる機会がこれから増えそうだ.

ログといっても所詮はテキストなので, Emacs を使いたい. そこで, ログ解析に便利そうな, 使えそうな機能をまとめてみた.

とくに, Java の log4j 専用というわけではなく, どんなテキストログの解析にも応用できればいいな.

閲覧

Read Only Mode

ログなので, Read Only でファイルを開きたい.

  • M-x toggle-read-only (C-x C-q) で現在開いているテキストを 読み取り専用にすることができる

  • M-x find-file-read-only で読み取り専用で開くことができる. 解除は, toggle-read-only で.

参考:

(add-to-list 'auto-mode-alist '("\\.log$" . read-only-mode))

Tramp

ログはサーバからダウンロードする. Emacs からサーバに直接乗り込んで開くためには, Tramp を利用する.

tail -f 的な

リアルタイムログ解析のためには, M-x auto-revert-tail-mode を利用. これで, tail -f のようにファイルを更新することが可能になる.

検索

複数ファイル検索: grep/ ag / helm-ag

検索は grep が基本.

最近は, grep よりも高速な検索ができる ag というものもある.

さらには, 絞り込みを helm I/F から利用するための helm-ag もある.

単一ファイル検索: helm-swoop

helm-swoop を利用すると, 一文字打ち込む度に検索が走る. ログサイズが小さいときや, 単一ファイルならば, grep よりも使いやすい.

インクリメンタル検索

isearch (C-s) が基本.

インクリメンタル検索である isearch と helm-swoop をつなぐ, ace-isearch というものもある.

ブックマーク/ ハイライト

Bookmarks をハイライト

行をハイライトできる.気になる行に色をつける.

本当は移動用なのだけれども, 色付けとして利用.

helm-all-mark-rings

C-SPC でマークをした場所を覚えておいて, helm で選択してジャンプできる.

(global-set-key (kbd "M-SPC") 'helm-all-mark-rings)

シンボルをハイライト

highlight-symbol/auto-highlight-symbol

シンボルをハイライトできる.気になる単語に色をつける.

(require 'auto-highlight-symbol-config)
(require 'highlight-symbol)
(setq highlight-symbol-colors '("DarkOrange" "DodgerBlue1" "DeepPink1"))

(global-set-key (kbd "<f3>") 'highlight-symbol-at-point)
(global-set-key (kbd "M-<f3>") 'highlight-symbol-remove-all)

hl-anything

永続的に, ハイライトを保持することが可能になる.

以下の記事の解説が詳しい.

(require 'hl-anything)
(hl-highlight-mode 1)

(global-set-key (kbd "<f2>") 'hl-highlight-thingatpt-local)
(global-set-key (kbd "M-<f2>") 'hl-unhighlight-all-local)

Java

以下参照.

28 Dec 2014, 15:59

Emacs 高速化起動にむけたカイゼンのとりくみ

はじめに

Emacs の起動を早くしたい. Windows 環境 (Cygwin) 環境における Emacs の起動時間が異常.

というわけで, 改善に向けた取り組みを実施した.

計測

起動時間の把握

M-x emacs-init-time という関数を実行すると, 起動にかかる時間がわかる.

とりあえず, 現状は

Machine Time


Arch Linux 12.1 Windows 29.6

esup をつかう

esup を利用すると, 詳細な起動時間がわかる.

(require 'esup)

自分の環境だと, inits ディレクトリ配下がすべて結果が要約されてしまい, よくわからなかった.

initchart をつかう

Emacs のスタートアップを視覚化する.

(require 'initchart)
(initchart-record-execution-time-of load file)
(initchart-record-execution-time-of require feature)

init log の確認

elisp の管理には init-loader.el を利用してる. init log を確認すると, 各処理における読み込み時間がわかる.

Windows における時間.

loaded c:/cygwin64/home/tsu-nera/dotfiles/.emacs.d/inits/00_el-get.elc. 0.0
loaded c:/cygwin64/home/tsu-nera/dotfiles/.emacs.d/inits/01_global.el. 2.2812822
loaded c:/cygwin64/home/tsu-nera/dotfiles/.emacs.d/inits/03_display.el. 1.0277368
loaded c:/cygwin64/home/tsu-nera/dotfiles/.emacs.d/inits/20_text.elc. 4.8438096999999996
loaded c:/cygwin64/home/tsu-nera/dotfiles/.emacs.d/inits/30_programming.elc. 1.8992336
loaded c:/cygwin64/home/tsu-nera/dotfiles/.emacs.d/inits/31_c_cpp.elc. 0.1406281
loaded c:/cygwin64/home/tsu-nera/dotfiles/.emacs.d/inits/31_haskell.elc. 0.2656291
loaded c:/cygwin64/home/tsu-nera/dotfiles/.emacs.d/inits/31_java.elc. 0.3750235
loaded c:/cygwin64/home/tsu-nera/dotfiles/.emacs.d/inits/31_python.elc. 1.9972729
loaded c:/cygwin64/home/tsu-nera/dotfiles/.emacs.d/inits/31_ruby.elc. 0.3281107
loaded c:/cygwin64/home/tsu-nera/dotfiles/.emacs.d/inits/33_minorlang.elc. 2.2702037
loaded c:/cygwin64/home/tsu-nera/dotfiles/.emacs.d/inits/40_helm.elc. 1.1719071
loaded c:/cygwin64/home/tsu-nera/dotfiles/.emacs.d/inits/50_org-mode.elc. 1.2500322
loaded c:/cygwin64/home/tsu-nera/dotfiles/.emacs.d/inits/60_utility.el. 7.3733458
loaded c:/cygwin64/home/tsu-nera/dotfiles/.emacs.d/inits/61_wanderlust.elc. 0.13878569999999998
loaded c:/cygwin64/home/tsu-nera/dotfiles/.emacs.d/inits/90_color.elc. 0.7656375
loaded c:/cygwin64/home/tsu-nera/dotfiles/.emacs.d/inits/99_windows8.elc. 0.171875
loaded c:/cygwin64/home/tsu-nera/dotfiles/.emacs.d/inits/windows-init.elc. 0.1406362

分析

  • utility が一番のボトルネック
    • 利用していないものはコメントアウト.
  • プログラミング言語に関する lisp は普段利用しないのに読み込みに時間かかかっている.
    • 遅延ロードをすべてに適用する
  • text 編集関係に時間がかかっている.
    • 利用しないものはコメントアウト

課題

当たり前の結果だけれども, 以下の 2 点に絞られるようだ.

  • 遅延評価の積極的適用
  • 不要な行の削除

カイゼン

emacsclient をつかう

これはつかう, というよりもすでにつかっている. というより, これをつかわないと話にならない.

ちなみに, 早く立ち上げたいときは, emacs -q オプションを指定することで設定ファイルを読み込まずに立ち上げる.

X Windows 環境での起動カイゼン

よくワカってないけど, コンナおまじないがあるらしい.

(modify-frame-parameters nil '((wait-for-wm . nil)))

バイトコンパイルをする

パッケージ管理には el-get を利用してる. そして, elisp の管理には init-loader を使っている.

el-get で取得したものは自動的にバイトコンパイルされるのだが, 盲点があった. それが

  1. el-get 自体
  2. init-loader 自体
  3. inits 配下の設定ファイル

1,2 については, el-get でいままで管理していなかった. これらを el-get 配下で管理するようにしていた.

さらに, inits 配下の設定ファイルについては 編集するたびにバイトコンパイルするようにした.

を参考にして, 以下を init.el に記述.

;;; 設定ファイルのあるフォルダを指定
(setq inits_dir (expand-file-name "~/.emacs.d/inits/"))
(init-loader-load inits_dir)

;; inits フォルダのみ, 保存時に自動コンパイルして即反映させる
;; http://fukuyama.co/emacsd
(defun auto-save-byte-compile-file ()
  "Do `byte-compile-file' and reload setting immediately, When elisp file saved only in inits folder."
  (interactive)
  (when (or (equal default-directory inits_dir)
        (equal default-directory (abbreviate-file-name inits_dir)))
    (byte-compile-file buffer-file-name t)
    ))
(add-hook 'emacs-lisp-mode-hook
      (lambda ()
        (add-hook 'after-save-hook 'auto-save-byte-compile-file
;; nil t)))

init-loader で自動バイトコンパイル機能があるようだ.

(setq init-loader-byte-compile t)

有効にしたが, イマイチ使い方がよくわからない.

起動時にバイトコンパイル

野良 elisp もバイトコンパイルしておいた方が早い.

init.el に以下を追記する. 末尾に 0 をつけることで, 起動時にバイトコンパイル.

(byte-recompile-directory "~/.emacs.d/myelisp" 0)
(byte-recompile-directory "~/.emacs.d/elisp" 0)

設定ファイルに直書きしている関数も外部ファイルに出してバイトコンパイル

これは結構効果的だった.

ステップ数の多い defun は別のファイルに分けた.さらに

  • 末尾に (provide ‘hogehoge) を追加
  • gist に登録
  • el-get で取得する recipe 作成

することで, gist で外部ファイルを管理することにした.

遅延ロードを適用する

autoload をつかう

ライブラリを起動時にロードする必要がない場合は, autoload を利用する. xxx-command を利用するときになって初めて”xxx”がロードされる.

(autoload 'xxx-command "xxx")

起動時にロードしないことで, 高速化.

eval-after-load/hook つかう

あるモードでのみ利用するものは, eval-after-load or hook を利用する.

;; hook
(add-hook 'c-mode-common-hook
      '(lambda ()
         (gtags-mode 1)
         (gtags-make-complete-list)))

;;eval-after-load
(eval-after-load "isearch"
  '(progn
     (require 'isearch-dabbrev)
     (define-key isearch-mode-map (kbd "<tab>") 'isearch-dabbrev-expand)))

2 つの違いは以下が詳しい.

要約すると,

  • 一度だけ設定すればよいものは eval-after-load
  • バッファを開くたびに設定したいもの hook

Emacs24.4 からは with-eval-after-load という関数がある. これも以下の記事が詳しい.

use-package をつかう

autoload/eval-after-load の記述を簡潔に書くための elisp.

記述方法は以下の記事がとても詳しい. ここでは省略.

起動時のエラーログや load ログを除去

起動時のログで怪しいものは極力調べて排除した.

結果

起動速度が半分になった! v (\^\^) v

Machine Time diff


Arch Linux 6.0 -6.1 Windows 16.7 12.9

リフリァクタリングした 設定ファイル

26 Dec 2014, 07:55

AWS の Amazon EC2 で Windows サーバを立ち上げて リモートデスクトップ接続してみた

はじめに

Amazon Web Service (AWS) をずっと試してみたかったので, 冬休みに試してみた.

以前, OpenStack を動かしてみた.今回はライバルを試す.

環境

  • ArchLinux

手順

まずは, アカウントを作成.

やりたいこと

Linux サーバと Windows サーバをお手軽に借りたい

利用できそうか?

AWS にはいろいろなサブコンポーネントがある.

これによると,

  • Amazon EC2 というものを選択すれば, 仮想サーバが利用できそうだ.
  • Amazon Lambda というものを利用すると,イベント駆動でサーバを制御できるようになる.

今回は, Amazon EC2 を利用してサーバを立ち上げる. 使うときに手動で立ち上げて, やめるときに手動で落とす.

Amazon Lambda を利用すると, EC2 を常時立ち上げていなくてもいいよう なので, コスト削減と自動化が達成できそうだが, 時間がかかりそうなので, 後回しとする.

料金

以下で料金が見積もれる. はじめの一年間は無料らしい.

Windows と Linux を最小構成で週 2 時間借りた場合は, 0.6 ドル??

Windows のインスタンスを作成

まずは 最小構成の Windows のインスタンスを作成してみる.

  • EC2 サービスを選択
  • Launch Instance を選択
  • Microsoft Windows Server 2008 R2 Base 64bit 選択
  • t2.micro を選択
  • あとはデフォルト設定で.
  • Launch をおすと Key Pair の作成を聞かれるので生成して, 選択.

参考

リモートデスクトップで接続

Linux 環境から Remote Desktop のクライアント rdesktop で接続してみる.

まずは, 接続に必要なパスワードを取得する. さっきダウンロードした Key Pair ファイルをアップロードすると, パスワードが表示される.

以下のコマンドで接続.

rdesktop -k ja (IPAddress) -u (Username) -p (Psssword)

Linux から Windows に接続できた!

24 Dec 2014, 12:03

プロクラミングパラダイムの意義と 2014 年のプログラミング言語の勉強まとめ

はじめに

edX で プログラミングパラダイムの講義を受けたのでその記録.

実は, この講座は受講が今回で 2 回目だ.前回受けたときの記録は以下.

なぜ 2 回も受けた?

理由は以下だ, 前回の講座で,

  • 単位を落とした…
  • 内容があまりにも素晴らしかった
  • 内容の理解をもっと深めたかった.

内容

内容は, 前回とまったく同じだった. スライドも動画も, そして問題も.

前回は 12week 連続で講義があったのに対して, 今回は 6week x 2 というように 2 つの講座に分かれていた.

あらためてパラダイムの整理

以下のようなパラダイムとコンセプトを順に説明していく.

Paradigms Concepts Features


Functional Programming Functions and recursion Hihger-order programming Single-assigned variables Object-Oriented Programming + cell Data Abstraction Polimorphism Inheritance Deterministic Dataflow Programming + thread No race conditions Concurrent transparency Streams and agents Multiagent Dataflow Programming + port Deterministic dataflow Nondeterminism where needed Active Object Programming + local cell Object-oriented programming Multi-agent dataflow

パラダイムを身につけることでどんな言語にも対応できる

この一年での言語の勉強記録

この 1 年で, たくさんの言語に触れた.

  • VBA (1 月)
  • Oz (3-4 月)
  • Scala (5 -6 月)
  • x86-x64 Assembly (7-8 月)
  • Python (9-10 月)
  • Haskell (11,12 月)
  • R (12 月)

2 ヶ月に 1 回は, 新しい言語に挑戦していた気がする.

また, 仕事で Ruby と Java をつかうようになって, オブジェクト指向言語を 利用することに対して抵抗がなくなった.

2 年前は C 言語しかできなかった

思い返せば, 2 年前は C 言語ただ一つしか使いこなすことができなかった.

このブログを始めたのが 2 年半前くらい. なんとなく, このままではダメだと思っていた.

去年はオブジェクト指向言語に触れようと思い, C++ と Ruby を独学で学んだ.

今年は関数型言語に触れようと思い, Scala や Haskell に触れた.

今では, 2 年前に感じていたような, 単一言語しかしらない劣等感がなくなっていた.

プログラミングを極める最良の方法とは

一つ一つ, 新しい言語に触れる度に, 理解するまでの時間が短くなっていくことを感じた. 言語のもつコンセプトの差異や共通点が見えてくるのが楽しい.

そして, そういう言語の妙を味わうための審美眼は, 間違いなくこの講座を受けることによって得たものだった.

プログラミング言語のコンセプトやパラダイムを身につけることが, 数多くの言語を身につけたり, 言語の本質を理解するための 効率のよい方法だということを, たくさんの言語に触れることで実感した.

この 1 年の最大の出会いは, CTMCP 本 (ガウディ本) に出会ったことだった.

これからどうするか?

CTMCP 本はいったん寝かせる

さらにプログラミングのコンセプトの理解を深めていきたい.

CTMCP 本を 2 回繰りかえして読んだのだが, まだまだ理解したとはいえない. 後半の方は読んでもいない.

ただ, edX があったからこそ読み進めることができたけれども, 一人じゃなんだかこの先を読むにも心が折れて挫折しそうだ.

この本は, この先も何度も何度も読み返していくことになるだろう. なので, いったん読むのを止めて, 別の本を読んでみようと思う.

最近発売された軽めの本

最近, コーディングを支える技術という本の電子書籍版 が出たのでこれを読んでみる.

電子書籍版は技術評論社の HP から.

目次を読む限り, 内容的にも重量的にも軽そうだ.

ガウディ本のライバル魔術師本

この CTMCP 本の前に出版された, 似たようなコンセプトでかかれた本がある.

通称, SICP 本, 魔術資本.これを来年読んでみる.

この本を扱った edX の講座と MIT のオンライン講義を見つけた. この講座のどちらかをベースにしつつ, 読んでみるつもりだ.

UC Berkeley: CS 61AS Structure and Interpretation of Computer Programs :SICP:

MIT courseware: Structure and Interpretation of Computer Programs

22 Dec 2014, 13:23

Emacs で R 言語を利用するための設定メモ (ESS)

はじめに

最近, 統計学と R 言語をさわり始めた.

なぜなら, 本屋にいくとビッグデータやら, データマイニングやら, データサイエンティストやら, そんな単語がポンポン目に入るから.

ということで, まずは Emacs で R 言語を快適に利用するための設定をしてみた.

もちろん, RStudio なんて便利なものは知っているがね.

ESS

Emacs を統計用 IDE にするツール. デファクトスタンダードと言えよう.

起動は M-x R.

(setq load-path (cons "/usr/share/emacs/site-lisp/ess" load-path))
(when (locate-library "ess-site")
  (require 'ess-site)

(setq auto-mode-alist
      (cons (cons "\\.[rR]$" 'R-mode) auto-mode-alist))
(autoload 'R-mode "ess-site" "Emacs Speaks Statistics mode" t)


;; R 起動時にワーキングディレクトリを訊ねない
(setq ess-ask-for-ess-directory nil)

ESS Auto-complete

R 言語の入力自動補完をするために, auto-complete を利用する.

(when (locate-library "ess-site")
(setq ess-use-auto-complete t)
;; (setq ess-use-auto-complete 'script-only)
)

ESS R Data View

データの中身がみれる.

;; (define-key ess-mode-map (kbd "C-c v") 'ess-R-dv-ctable)
(define-key ess-mode-map (kbd "C-c v") 'ess-R-dv-pprint)

popwin と組み合わせると便利.

ess-R-object-popup

オブジェクトの中身をポップアップで表示.

(when (locate-library "ess-site")
(require 'ess-R-object-popup)
(define-key ess-mode-map "\C-c\C-g" 'ess-R-object-popup)
)

gist 版は古いようだ.

no ESS process is associated with this buffer というエラー がでたら C-c C-s を叩く.

helm-R

helm インタフェースで 関数のヘルプをひくことができる.

(when (locate-library "ess-site")
(require 'helm-R)
(define-key ess-mode-map "\C-ch" 'helm-for-R)
(define-key inferior-ess-mode-map "\C-ch" 'helm-for-R)
)

org-babel-R

org-mode で R を利用する.

(when (locate-library "ess-site")
(org-babel-do-load-languages
 'org-babel-load-languages
 '((R . t)))
)

R 言語と org-mode で Reproducible Research を.

以下のようにタグでソースを加工する. C-c C-c で評価する.

#+begin_src R :file age_at_intake.png :width 400 :height 400 :results graphics

#+end_src

おわりに

半分以上のパッケージが myuhe さんが作成したものだと気づく. すごい. Special Thanks!

19 Dec 2014, 12:18

Java の Map で byte 配列をキーにするときの注意点

はじめに

Java で HashMap のキーに byte[] 配列を利用したら, key を put しても containsKey で key がないよといわれてしまった.

static void testbyteMap () {
    Map<byte[], Integer> map = new HashMap<byte[], Integer>();
    byte[] key = {1,2,3};
    byte[] key2 = {4,5,6};
    byte[] key3 = {1,2,3};

    map.put (key,1);
    map.put (key2,2);

    System.out.println (map.containsKey (key));
    System.out.println (map.containsKey (key2));
    System.out.println (map.containsKey (key3));
}

結果

true
true
false

調査

どうも配列を入れても, うまく検出できないようだ.

同一オブジェクトだと, 大丈夫だが, 値が同じでも違うオブジェクトだとだめ.

static void testIntMap () {
    Map<int[], Integer> map = new HashMap<int[], Integer>();
    int[] key = {1,2,3};
    int[] key2 = {4,5,6};;
    int[] key3 = {1,2,3};;

    map.put (key,1);
    map.put (key2,2);

    System.out.println (map.containsKey (key));
    System.out.println (map.containsKey (key2));
    System.out.println (map.containsKey (key3));
}

解決策

原因は, byte[] が 大小比較できないから.

Stack Overflow によると

  • byte[] を String に変換
  • byte[] をを List<Byte>に変換
  • equals と hashmap を実装した ラッパーデータ型を作成

String 変換を試す

一番お手軽なのは, String 変換か?

static void testStringMap () throws UnsupportedEncodingException {
    Map<String, Integer> map = new HashMap<String, Integer>();
    byte[] key = {1,2,3};
    byte[] key2 = {4,5,6};
    byte[] key3 = {1,2,3};

    String keyStr = new String (key, "UTF-8");
    String keyStr2 = new String (key2, "UTF-8");
    String keyStr3 = new String (key3, "UTF-8");        

    map.put (keyStr,1);
    map.put (keyStr2,2);

    System.out.println (map.containsKey (keyStr));
    System.out.println (map.containsKey (keyStr2));
    System.out.println (map.containsKey (keyStr3));
}

static void testStringMap2 () throws UnsupportedEncodingException {
    Map<String, Integer> map = new HashMap<String, Integer>();
    byte[] key = {1,2,3};
    byte[] key2 = {4,5,6};
    byte[] key3 = {1,2,3};

    String keyStr = Arrays.toString (key);
    String keyStr2 = Arrays.toString (key2);
    String keyStr3 = Arrays.toString (key3);        

    map.put (keyStr,1);
    map.put (keyStr2,2);

    System.out.println (map.containsKey (keyStr));
    System.out.println (map.containsKey (keyStr2));
    System.out.println (map.containsKey (keyStr3));
}

結果

これで OK.

true
true
true

Special Thanks

18 Dec 2014, 15:44

Java での再帰処理で Stack Overflow を回避するためのエセ方法

はじめに

最近, haskell の勉強をしている関係上, Java でも再帰が使いたい.

しかし, Java で 再帰処理を書くと, いつか必ず StackOverflowError がでて プログラムが強制終了してしまう.

回避方法がないものか, 調べてみた.

検証

コード

public class RecursiveSample {
    public static void main (String args[]) {
        recursiveProcedure (1);
    }

    static void recursiveProcedure (int i) {
        try {
            System.out.println (i);
            recursiveProcedure (i+1);
        }
        catch (Throwable e) {
      System.out.println ("Error " + e.getMessage ());
      e.printStackTrace ();
        }
    }
}

実行結果

9917
9918
9919Error null
java.lang.StackOverflowError
at java.util.concurrent.locks.AbstractOwnableSynchronizer.<init>(AbstractOwnableSynchronizer.java:59)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.<init>(AbstractQueuedSynchronizer.java:299)
at java.util.concurrent.locks.ReentrantLock$Sync.<init>(ReentrantLock.java:119)
at java.util.concurrent.locks.ReentrantLock$NonfairSync.<init>(ReentrantLock.java:203)
at java.util.concurrent.locks.ReentrantLock.<init>(ReentrantLock.java:262)
at java.util.concurrent.ConcurrentHashMap$Segment.<init>(ConcurrentHashMap.java:425)
at java.util.concurrent.ConcurrentHashMap.ensureSegment (ConcurrentHashMap.java:749)
at java.util.concurrent.ConcurrentHashMap.putIfAbsent (ConcurrentHashMap.java:1149)
at java.lang.ClassLoader.getClassLoadingLock (ClassLoader.java:464)
at java.lang.ClassLoader.loadClass (ClassLoader.java:405)
at java.lang.ClassLoader.loadClass (ClassLoader.java:412)
at sun.misc.Launcher$AppClassLoader.loadClass (Launcher.java:308)
at java.lang.ClassLoader.loadClass (ClassLoader.java:358)
at RecursiveSample.recursiveProcedure (RecursiveSample.java:9)
at RecursiveSample.recursiveProcedure (RecursiveSample.java:9)
at RecursiveSample.recursiveProcedure (RecursiveSample.java:9)

所感

あちゃー.

再帰階層に上限をつけてみる

問題は, 深すぎる再帰呼び出しにある. ある程度深くなったら, 一旦関数呼び出しから戻って, 再会してみる.

コード

  public class RecursiveSample {
    static int recursiveMax;
    static int recursiveCount;

    public static void main (String args[]) {

        try {
            while (true) {
                    recursiveMax += 10000;
                    recursiveCount = recursiveProcedure2 (recursiveCount);
            }
        } catch (RecursiveEnd e) {
            System.out.println ("End");
        }

    }

    static int recursiveProcedure2 (int recursiveCount) throws RecursiveEnd {
        if (recursiveCount == 50000) throw new RecursiveEnd ();

        if (recursiveCount < recursiveMax) {
            System.out.println (recursiveCount);
            return recursiveProcedure2 (recursiveCount+1);
        }
        else {
            return recursiveCount;
        }
    }
}

class RecursiveEnd extends Exception {
}

所感

loop を結局つかっていて, かっこわるい… でも一応再帰も使えている.

終了条件にマッチしたら例外を発生させて, コンテキストから飛び出すところがミソ.

17 Dec 2014, 16:20

Java で log4j の使ってみた (Eclipse, Emacs Viewerも)

はじめに

仕事で log4j を利用しているので, Eclipse での使い方を少し調べてみた.

環境

  • log4j 2.3
  • Eclipse 4.4
  • Java 1.7

log4j とは

Java で, ログを残すための便利で有名なライブラリ.

install

以下から最新版をダウンロード.

設定

適当なところに解凍後, クラスパスを通す.

Eclipse だと,

  • ツールバー > ウィンドウ > 設定
  • Java > ビルド・パス > ユーザライブラリ
  • 新規 -> Log4j と入力
  • 外部 Jar 追加 を選択
    • 以下を登録
      • log4j-core-2.x.jar
      • log4j-api-2.x.jar
      • log4j-1.x-api-2.x.jar

続いて, プロジェクトを右クリックして,

  • プロバティ > Java ビルド・パス > ライブラリータブ
  • ライブラリー追加 > ユーザライブラリ > 次へ
  • 上で作成した Log4j を追加.

Hello log4j

標準出力に log を出すことを目指す.

log4j2.xml を作成.

以下を参考に logger.xml を作成して, src 配下に配置.

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
  <Appenders>
    <Console name="Console" target="SYSTEM_OUT">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </Console>
  </Appenders>
  <Loggers>
    <Root level="trace">
      <AppenderRef ref="Console"/>
    </Root>
  </Loggers>
</Configuration>

<Root level=“xxxx”>を調整することで, ログレベルを調整できる.

ログレベル

Wikipedia から引用. 以下のようにログのレベルがある.


Fatal 致命的なエラー. プログラムの異常終了 ERROR エラー. 予期しないその他の実行時エラー WARN 警告. INFO 情報. 実行時の何らかの注目すべき事象 DEBUG デバッグ用の情報 Trace トレース情報. DEBUG よりも詳細な情報


コードを作成

サンプルコード作成.

package sample;
import org.apache.log4j.Logger;

public class LoggerSample {
        public static void main (String[] args) {
        Logger logger = Logger.getLogger (LoggerSample.class.getName ());

        logger.trace ("Hello trace");
        logger.debug ("Hello debug");
        logger.info ("Hello info");
        logger.warn ("Hello warning");
        logger.error ("Hello error");
        logger.fatal ("Hello fatal");
    }

出力結果

23:57:03.111 [main] TRACE sample.LoggerSample - Hello trace
23:57:03.112 [main] DEBUG sample.LoggerSample - Hello debug
23:57:03.112 [main] INFO  sample.LoggerSample - Hello info
23:57:03.112 [main] WARN  sample.LoggerSample - Hello warning
23:57:03.112 [main] ERROR sample.LoggerSample - Hello error
23:57:03.112 [main] FATAL sample.LoggerSample - Hello fatal

Eclipse Plugin

Eclipse で log4j のログを表示させるプラグインはいくつかあるみたい.

JLV

JLV を試す. ためそうと思ったらこれは, log4j 1.x 用だったので, 1.x を入れる.

以下にしたがって設定.

カラフルに色が表示される. 検索機能も便利.

Emacs Lisp

こんなのみつけた.

text におとした log をみるモード. 自動で更新されるのもよい.

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" >

  <appender name="file" class="org.apache.log4j.FileAppender">
     <param name="File" value="./sample.log" />
     <param name="Append" value="true" />
     <param name="Encoding" value="Shift_JIS" />
     <layout class="org.apache.log4j.PatternLayout">
        <param name="ConversionPattern" value="%m%n" />
     </layout>
  </appender>

  <root>
    <appender-ref ref="file"/>
  </root>
</log4j:configuration>

helm-swoop とかとくみあわせると, 抜群の検索効果.

JTags と組み合わせると, なんと Log からソースへジャンプできる.

BookMark

14 Dec 2014, 08:51

データフロー変数 (Oz) で実現する Producer-Consumer Pattern

はじめに

以下の記事の続編です.

前回は, Java の 共有メモリモデルを利用して Producer-Consumer Pattern を実装した.

今回は, Oz のもつ決定性データフローモデルを利用して実装してみる.

決定性データフローモデル

データフロー変数をもつモデル.

データフロー変数

<div class="outline-text-3" id="text-unnumbered-3">
  <p>
    変数に値が束縛されるまでプログラムの実行を待ち合わせるような宣言的変数.
  </p>

  <p>
    あるスレッドがデータフロー変数を利用しようとしたとき, その変数に値が束縛されていない場合は, 別のスレッドが束縛するまで待ち合わせを行う.
  </p>

  <p>
    束縛されたときの実行を データフロー実行 という.
  </p>
</div>

実行例

Java

<div class="outline-text-3" id="text-unnumbered-5">
  <p>
    まずは, Java でのサンプル. 平行性を実現するためには, キューを共有する.
  </p>

  <p>
    結構コードがながくなってしまった&#x2026;
  </p>

  <p>
    [sourcecode language=&#8221;java&#8221; title=&#8221;&#8221;]<br /> import java.util.concurrent.LinkedBlockingQueue;<br /> import java.util.concurrent.BlockingQueue;<br /> import java.util.LinkedList;<br /> import java.util.List;
  </p>

  <p>
    public class ProducerConsumerPattern {<br /> public static void main (String args[]) {<br /> BlockingQueue<List<Integer>> queue = new LinkedBlockingQueue<List<Integer>>();
  </p>

  <p>
    Producer producer = new Producer (queue, 10);<br /> Consumer consumer = new Consumer (queue);
  </p>

  <p>
    producer.start ();<br /> consumer.start ();<br /> }<br /> }
  </p>

  <p>
    class Producer extends Thread {<br /> BlockingQueue<List<Integer>> queue;<br /> List<Integer> list;<br /> int limit;
  </p>

  <p>
    public Producer (BlockingQueue<List<Integer>> queue, int limit) {<br /> this.queue = queue;<br /> this.limit = limit;<br /> list = new LinkedList<Integer>();<br /> }
  </p>

  <p>
    public void run () {<br /> try {<br /> for (int i=1; i <= limit; i++) {<br /> System.out.println (i);<br /> sleep (1000);<br /> list.add (i);<br /> }<br /> queue.put (list);<br /> }<br /> catch (Exception e) {}<br /> }<br /> }
  </p>

  <p>
    class Consumer extends Thread {<br /> BlockingQueue<List<Integer>> queue;<br /> Integer sum;<br /> public Consumer (BlockingQueue<List<Integer>> queue) {<br /> this.queue = queue;<br /> this.sum = 0;<br /> }
  </p>

  <p>
    public void run () {<br /> try {<br /> List<Integer> list = queue.take ();<br /> for (Integer i: list) {<br /> sum += i;<br /> }<br /> System.out.println (sum);<br /> }<br /> catch (Exception e) {}<br /> }<br /> }<br /> [/sourcecode]
  </p>
</div>

Oz

<div class="outline-text-3" id="text-unnumbered-6">
  <p>
    つづいて, データフロー変数をサポートする Oz.
  </p>

  <p>
    とてもシンプルにかつ安全に書くことができる. データフロー変数の未来を感じることができるコード.
  </p>

  <p>
    [sourcecode language=&#8221;ruby&#8221; title=&#8221;&#8221;]<br /> declare<br /> fun {Producer N}<br /> fun {Producer1 X N}<br /> {Delay 1000}<br /> if X < N+1 then<br /> {Show X}<br /> X|{Producer1 X+1 N}<br /> else nil<br /> end<br /> end<br /> in<br /> {Producer1 1 N}<br /> end
  </p>

  <p>
    fun {Consumer S}<br /> fun {Sum S Acc}<br /> case S of X|Xr then {Sum Xr Acc+X}<br /> [] nil then Acc<br /> end<br /> end<br /> in<br /> {Sum S 0}<br /> end
  </p>

  <p>
    local Xs Ys S in<br /> thread Xs = {Producer 10} end<br /> thread<br /> Ys = {Consumer Xs}<br /> {Show Ys}<br /> end<br /> end<br /> [/sourcecode]
  </p>
</div>

13 Dec 2014, 03:54

Adapter, Facade, Proxy パターンの違いのメモ

はじめに

Gof のデザインパターンで Adapter, Facade, Proxy があり, 違いがわからなかったので, 整理してみた.

まずは定義から

Adapter

インタフェースを変換することにより, インタフェースに互換性がない クラス同士を接続する.

既存のクラスに対して修正を加えることなく, インタフェースを変更することができる.

継承を利用する場合と委譲を利用する場合がある.

Facade

複数のクラス群からなるサブシステムにアクセスするための, インタフェースを提供する.

異なるサブシステムを単純な操作だけを持った Facade クラスで結び, サブシステム間の独立性を高める事を目的とする.

facade とは, 正面という意味.

Proxy

オブジェクトへのアクセスをフックするための代理オブジェクトを提供する.

Proxy は英語で代理人.

ラッパー

ラッパーという概念がある.

あるクラスや関数, データ型などが提供する機能やデータを含み, 別の形で提供するもののこと.

どれもラッパーと言える.

オブジェクト思考のこころより

オブジェクト思考のこころという本に, Adapter と Facade の比較表がある.

以下, Proxy パターンも交えて整理すると,

  • Facade はインタフェースを簡素化する
  • Adapter は既存インタフェースを他のインタフェースに変換する
  • Proxy はインタフェースを変更せずに機能追加する.

                                                    Facade   Adapter   Proxy
    

    既存クラスがある? ○ ○ ○ インタフェースを再設計する? × ○ × ボリモーフィズムによるオブジェクトの振る舞いが必要? × ○ × より簡素なインタフェースが必要? ○ × ×

コードでの例

class Target {
    void printInt (int i) {
        System.out.println (i);
    }

    void printLong (long l) {
        System.out.println (l);
    }
}

class Adapter {
    Target target;
    Adapter (Target target) {
        this.target = target;
    }

    void printInt (Integer i) {
        target.printInt (i);
    }

    void printLong (Long l) {
        target.printLong (l);
    }

}

class Facade {
    Target target;
    Facade (Target target) {
        this.target = target;
    }

    void print (long l) {
        target.printLong (l);
    }
}

class Proxy {
    Target target;
    int intCount = 0;
    int intCache= 0;
    long longCount = 0;
    long longCache = 0; 

    Proxy (Target target) {
        this.target = target;
    }

    void printInt (Integer i) {
        target.printInt (i);
        intCount++;
        intCache = i;
    }

    void printLong (Long l) {
        target.printLong (l);
        longCount++;
        longCache = l;
    }
}