log4jの設定について。

Java/log4j

log4jの設定について。

log4jの設定ファイル(log4j.xmlとlog4j.propertiesがあるけどここではpropertiesについて。xmlについては適宜読み替えて下さい)の設定について。

log4jの基本的な使い方やpropertiesの基本的な書き方は他にちゃんと詳しくてこのブログのように胡散臭くないサイトさんやブログがあるのでそちらに譲るとして。今回は私の備忘録です。
今まであんまり真面目に勉強してこなくて、そのツケが回りに回って調査に一日かかった…orz

log4jの設定は、
・Category(Logger)
・Appender
・Layout
の3つからなる。
■Appenderは、出力情報の設定。
出力ログのファイルパスや、追加で出力するとか上書きするとかの設定や、日次でファイル変えていくだのそういった辺りを設定。
■Layoutは、Appenderにくっついていて、出力するログのレイアウト(日時出してログ出力クラス名出して、とかの出力される1行ログの書式)。
Appenderの下にいるのに、設定はこの3つからなる!てAppenderと肩並べてるのはAppender的に思うところもあるだろうなぁ。
■Categoryは、Javaのソースに記述されるログの設定名みたいなもの、と理解。
log4j.category.FOR_DEBUG=DEBUG, a1,a2
と書くと、"FOR_DEBUG"という名前のカテゴリのログレベルはDEBUGで、Appenderにはa1とa2を指定、という意味。
Appenderは複数指定可能。a1がコンソール出力、a2がファイル出力、という感じで区別すると良い。
Javaの方では、
Logger debugLogger = Logger.getLogger("FOR_DEBUG");
(なんかソース)
debugLogger.debug("でばっぐ");
という風に書く。

で、CategoryとLoggerの関係については分かったような情報が曖昧なような。
一応、LoggerはCategoryを継承しているので、実体としてはまぁ違いはないよ、と。
但し、Categoryは非推奨化していて、その内消え去る運命だということで、log4jのバージョンによって、CategoryとLoggerを使い分けないといけないとのことです。
この辺りから若干情報が怪しくなってくる(^^;)
ソースが教えてgooしかないとかそんなレベルです。まぁこの辺りはあまりまじめに調べてないのですすみません。。。
今回のアプリの設定ファイルではrootLogger宣言して、log4j.categoryを設定して、JavaではLoggerクラスを使ってる。この入り乱れてるのが普通なのか統一すべきなのかの判断が付かないのですが、今回は元が私が作ったアプリでないので、あまり大きな変更勝手に加えると怒られるので放置してます。
ネットって解決策は見つかることが多いけど、それが「普通」のやり方なのかを判断するのは難しいですヨネ。

話が逸れましたが。

で、category設定で少し悩んだのが、log4j.category[logger].xxxと記述するところの xxx 部分に、パッケージを書くんだ、と書いているサイトが多かったこと。
例えば、log4j.category[logger].com.foo.bar とか。すんごい適当ですが。
まず、誤解しそうになりますが、「パッケージを書く」というのは「書かなければいけない」ではないということ。
前述した例のように、適当な名前を付けてもOKです。
むしろこっちの方が分かりやすいような気も私はするんだけど…うーん。
利点は、パッケージのように、"."で繋げて書くと、設定の継承が使えるトコロ。
log4j.category[logger].com.foo.barは、log4j.category[logger].com.foo の設定を継承できます。
後は、例えばSQLを発行しているような共通部分のクラスのパッケージ名を書いてやって、レベルをDEBUGにしておくと、SQLがDEBUGログに出力されるとか。
で、Logger.getLogger()については、
・Logger.getLogger(String)
・Logger.getLogger(String, LoggerFactory)
の他に、
・Logger.getLogger(Class)
をというコンストラクタがあって、中でクラス名を取ってくれているのです。
具体的には Logger.getLogger(this.class); とか書いてやればOK。
これのお陰で、「パッケージを記述する」ってのが簡単に使えている、という背景もあるんだろうけれど。

後書いておきたいのが、ルートロガーとその他のカテゴリ(ロガー)の関係。
というか、ルートロガーに何が出力されるのかがもう分かんなくて分かんなくて。
(……でも書いてる内容間違ってるって!って場合は是非教えて頂ければ幸いです。)

まずカテゴリで設定されているログを、アプリログ、それ以外のクラス(例えばPreparedStatement.classとか)から出力されているログを、共通ログと定義します(名前が適切でないなどの突っ込みはご容赦下さい。。。)。

で、以下ルートロガーと各カテゴリとの関係。
(やっぱりルートカテゴリ-各カテゴリ、ルートロガー-各ロガー、って組み合わせにしないといけないような気がするなぁ…)

(1)アプリログはルートロガーで設定されているログレベルに関わらず、すべて出力される。但し、対象ログが各カテゴリで設定されているログレベルに満たなくて、各アプリログに出力されない場合はルートログにも出力されない。
(2)共通ログは、ルートロガーのログレベル以上の場合だけ出力される。
(3)log4j.properties に設定されていないカテゴリ名で出力されるログ
 例:Logger.getLogger("UNKNOWN");
 このUNKNOWNがlog4j.propertiesに設定されていない
…については、ルートロガーのログレベル以上の場合だけ出力される。

当然ながら、アプリログについては、各カテゴリで設定されているログレベル以上のログしか各Appenderには出力されない。

なので、開発環境→本番環境などで、ログレベル云々ではなく該当カテゴリに含まれるログすべてを出力したくない場合、そのカテゴリをコメントアウトしたり削除したりするのではなく、カテゴリに設定されているログレベルを上げることで対応すること。
そうでないと、出力先がないのでルートログに出力しておく、という判断になってすべてのログがルートログにでることになる(前述の通り、ルートロガーのログレベルにも依るけど)
まぁルートロガーを空にしておくと何も出ないんだけど。。。多分、出そうとして文字列の生成まではいくので、パフォーマンスに影響が出るような気がします。
ちゃんと調べてなくてアレですが。

まぁ、結論としては
log4j.category.FOR_DEBUG=DEBUG,a1
などの場合、
log4j.category.FOR_DEBUG=FATAL,a1
などにしてやると良い、ということです。なんか気持ちは悪いけども…

まとまりないですが、備忘録。
間違っていたらまた修正しにきます~

| | コメント (0) | トラックバック (0)

selectall_arrayref の使い方

perl/DBI

Perl-DBI…サイトを色々見ててもかゆい所に手が届きづらい感じなのはなんなんだろうか…orz

selectall_arrayref の使い方ですっごい躓いたので備忘録。
selectall_arrayref の引数は以下。
1:SQL文字列
2:取得形式
3:バインド変数

ここで躓いたのは2なんですが……

各サイトでよっく見かけた記述が「\%attr」…つったってだからそのアトリビュートに何入れるんだっつー話ですよコレが。
分かんねぇよ!……みんな分かってんのかな……まぁAPIちゃんと読めよという話なんでしょうか。うーん。

http://blog.scrapcode.net/article/598613.html
↑こちらのブログでようやくとっかかりを見つけました。これも間違ってないんですが不十分…
こちらでは、「{Columns => {}}」を渡せと書いてあります。空のハッシュです。これに詰めて配列にして返してねってことみたいです。

で、最終的にたどり着いたのがこちら。
http://yanor.net/wiki/index.php?Perl-DBI%2FSELECT

目から鱗がボロボロボロボ。ホントに有り難うございました。
パターンとしては以下。
・未指定 :配列の配列(※バインド変数有りの時は指定出来ない気がします。未確認)
・{Slice=>[]} :配列の配列
・{Slice=>{}} :ハッシュの配列
・{Columns=>{}} :ハッシュの配列
・{Slice=>[0, 1]} :配列の配列(1カラムめと2カラムめのみ)
・{Columns=>[1, 2]} :配列の配列(1カラムめと2カラムめのみ)(※Columnsだと1カラムめのインデックスが1になる)
・{Columns=>{id=>undef, name=>undef}} :ハッシュの配列(id列とname列のみ)

[ ] と書くと配列で、{ } と書くとハッシュで取得。
Slice と Columns では、配列のインデックスが違う、という感じ。

ソース例:
my $sql   = "SELECT ID, NAME FROM M_MEMBER WHERE SEX = ? AND AGE < ?";
my @param = ('MALE', 30);

# SQL実行(配列の配列のリファレンスを取得)
$rRows    = $$myDbh -> selectall_arrayref($sql, {Slice => []}, @param);

my @rows = @$rRows;  # @rows は配列の配列

# このあたりにfor文入れるハズ
my $rRow = $rows[0]; # $rRow は1件めの配列のリファレンス
my @row  = @$rRow;   # @row  は1件めの配列
print "$row[0]<BR>";

私はあんまり使わない気がするけど、selectall_hashref もちょっと面倒な書き方でした。上のサイトさん消えないと良いなあ…(^^;)

| | コメント (0) | トラックバック (0)

SQLの実行計画の取得方法

ORACLE/SQL/実行計画取得

★実行計画を取得したい場合は
EXPLAIN PLAN FOR
<<取得したいSQL>>
の後、↓をSQL*Plusで実行

@C:\oracle\product\10.2.0\client_1\RDBMS\ADMIN\UTLXPLS.SQL

| | コメント (0) | トラックバック (0)

ヒープサイズの設定メモ

Weblogic/ヒープサイズ

今業務でやってるシステムで、数ヶ月前にOutOfMemoryエラーが発生したので原因調査をしたのですが。まぁ余り建設的な改善案は見当たらなかったのですが、色々調べたのでそれをメモ。全然まとまってませんというかただのリンク集です。

原因ではなかったのですが、調査中、この環境でこのシステム動かすのってどうなんだろうかと思ったり…まぁ環境周りは全然詳しくないのでなんともいえません。。。

以下当時のメモそのまま。

http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?mode=viewtopic&topic=27765&forum=12&start=8
http://www.atmarkit.co.jp/fjava/rensai2/webopt09/webopt09.html
http://www.atmarkit.co.jp/fjava/rensai3/devedge06/devedge06_2.html
http://www.atmarkit.co.jp/fjava/rensai3/javavm02/javavm02_2.html
http://edocs.beasys.co.jp/e-docs/wls/docs81/perform/JVMTuning.html#1131866

weblogicでは、startWebLogic.shのJAVA_OPTIONSにヒープサイズの設定を行う。
-mx512m
でヒープ領域を512Mにする、という設定になる。
以下参照
http://www.whitemark.co.jp/tec/java/javaHeap.html

現在の初期ヒープサイズは512MBになっているはず。もう少し割り当てられないか確認。

http://www.whitemark.co.jp/tec/java/javagc.html
http://www.smg.co.jp/JavaTroubleshooting/column_002Main.html
http://www.atmarkit.co.jp/fjava/rensai4/troublehacks08/troublehacks08_2.html
http://www.atmarkit.co.jp/fjava/rensai4/troublehacks01/troublehacks01_2.html#04

| | コメント (0) | トラックバック (0)

現在のフォルダをカレントディレクトリとしてコマンドプロンプトを起動する方法

Windows/コマンドプロンプト

エクスプローラ上で、フォルダを右クリックすると出てくるメニューに『コマンドプロンプト』を表示させて、それを選択すると現在のディレクトリをカレントディレクトリとしてコマンドプロンプトを起動させる方法です。
会社で新しいマシンもらったりお客さんトコ行ってマシン借りたり(長期間ね)する時にいっつもネットで調べるのでそろそろ書いておこうかなと。

コマンドプロンプトってant実行する時とかしかあんまり使わないですけど(^^;)家ではdirコマンドかpingコマンドしか打たないですけど(苦笑)地味に使うから絶対設定するんですよねー。

方法としては、レジストリを変更です。
1)ファイル名を指定して実行→regeditでレジストリエディタを起動。

2)HKEY_CLASSES_ROOT→Directry→shell

3)shellを右クリックで[新規]-[キー]選択で「cmd」という名前のキーを作成

4)作成したcmdの右ペインに表示される(既定)をダブルクリックして、値に「コマンドプロンプト」と入力
※ここで入力した値は、フォルダ選択で右クリック時に表示されるメニューに表示される文言です。まぁ別段何でも良いです『DOSプロンプトたん』とかでも良いです。

5)更にcmdを右クリック[新規]-[キー]選択で「command」という名前のキーを作成

6)作成したcommandの右ペインに表示される(既定)をダブルクリックして、値に「cmd.exe /k "cd %l"」と入力
※ここで入力した値は、実際に「コマンドプロンプト」を選択した時に実行されるコマンドです。

で、再起動というか再ログインでOK。
一回設定したら次に設定する時は初期化or新マシンゲット時なので、結構間開くんですよねー。覚えてられない(^^;)

| | コメント (0) | トラックバック (0)

PL/SQL のプロシージャ(ファンクション)をSQL*Plusなどから実行する方法

ORACLE/PL/SQL/SQL*Plus

(1)OUT引数と戻り値を宣言する
(2)EXECUTE、またはCALLコマンドで実行する
(3)正常に完了すると、「PL/SQLプロシージャが正常に完了しました」みたいなメッセージが出るので、その後OUT引数や戻り値をPRINTコマンドで確認するとOK

[例]
variable vOut1 VARCHAR2(20);
variable vOut2 VARCHAR2(20);
variable vRet number;
execute :vRet := [パッケージ名].[ファンクション名]('temp', [IN引数] , :vOut1, :vOut2);

PL/SQLプロシージャが正常に完了しました

print :vRet;
print :vOut1;
print :vOut2;

| | コメント (0) | トラックバック (0)

SQL パフォーマンスチューニング[一時保存]

参照

http://www.atmarkit.co.jp/fdb/rensai/orasql07/orasql07_1.html

| | コメント (0) | トラックバック (0)

SQL パフォーマンスチューニング

oracle/パフォーマンスチューニング

SQLのパフォーマンスチューニングでちょこっと調べたりしたこと。
備忘録です。
引用元↓↓↓↓
http://enterprisezine.jp/article/detail/30

実行計画とは…
引用ここから----->
>実行計画とは、SQL文を実行するために順番に実行される一連の操作手順のことです。サーバープロセスは実行計画に従って、SQL文を実行していきます。実行計画の中では、例えば索引を使用するのか(もしくは使用しないのか)、2つの表を結合させて検索する場合にどちらの表を先に検索するのか、結合にはどの方法を使用するのか、といったことが示されています。
>この実行計画は「オプティマイザ」によって作られます。オプティマイザとはSQL文を解析してデータを最も効率的に検索できる方法を探し、処理の順序を決定するエンジンです。Oracleは、「ルールベース」と「コストベース」という2種類のオプティマイザを持っています。
<-----引用ここまで

更にルールベースとコストベースの違いについても以下引用。
引用ここから----->
>ルールベースオプティマイザ
>ルールベースとは、あらかじめ決められたルールに基づいて最適化された実行計画を作成する方法です。SQL文の内容(書き方)によって、適用されるルールが変化します。そのため、実行効率の良いSQL文の書き方を考慮することが必要です。
>ルールベースのメリットは、例えば索引があったら索引を使うなど、動作が直感的で分かりやすい点です。一方で、データの状況によっては索引を使用しないほうが検索が速い場合にも、必ず使用されてしまうなどのデメリットがあります。そのため、使用は推奨されていません。
>Oracleのルールベースオプティマイザは、バージョン7.2で仕様が凍結されており、バージョン7.3以降のパーティション表や索引構成表など、いくつかの機能を使用できません。また、Oracle DB 10gではサポート外となっています。

>コストベースオプティマイザ
>コストベースとは、統計情報(後述)を基に各アクセス方法のコスト(処理の負荷)を計算して、最もコストが低い実行計画を選び出す方法です。通常、データベースのデータは時間が経つにつれて増えていきますが、その値に偏りが生じていく場合があります。コストベースオプティマイザは、データの内容に応じて最適な実行計画をその都度検討してくれます。これにより、ルールベースで問題であった「索引を使うとかえって遅くなる」ケースでは、索引を使用しない実行計画を生成します。
>ただし、コストベースでは正確な統計情報がないと、最適な実行計画が生成されません。そのため、統計情報を定期的に更新する必要があります。
<-----引用ここまで

…で、Oracle10gではルールベースがサポート外ってことはコストベースが採用されてるってことなんですね。
てことで、統計情報を定期的に取らないといい感じにならないよ、てことなんですね……!
既存システムからのデータ移行で一気に7万件もデータ突っ込んでるのに統計情報を取り直してないのが悪いと、そう仰るのですね……!それで良いのかなあ。また何か分かったら追記します。

| | コメント (0) | トラックバック (0)

eclipse でjava classファイルの逆コンパイル

java / eclipse / 逆解析

まとめ。
eclipseで逆コンパイルをするにはJadclipseというプラグインを使用します。
他にも方法があるかもしれないですが、私はこれで上手くいったので他は調べてません。

必要なのは、Jadclipseのjarファイルと、実際動かすためのJad.exeの2つ。それぞれ以下から入手してください(2008.04.30.現在のアドレスです)

Jadclipse
http://jadclipse.sourceforge.net/wiki/index.php/Main_Page

jad.exe
http://www.kpdus.com/jad.html

ここで注意をしないといけないのは、Jadclipseのバージョンと、eclipseのバージョンを合わせておかないといけないということ。ずれていると設定しようとした時にエラーが発生してeclipseさんに怒られてしまいます。

で、まぁJadclipseはeclipseのpluginsフォルダに配置して、Jad.exeは…多分適当にどっかに配置して良いと思います。
私はeclipseフォルダの直下に配置しました。

その後、eclipseを起動して、
ウィンドウ > 設定 > Java > Jadclipse
 Path to decompiler というところに、Jad.exeを配置したアドレスを指定します。
 例)C:\test\eclipse\jad.exe
これでOK。eclipseのパッケージ・エクスプローラなどでclassファイルをダブルクリックすれば逆解析してくれます。

自分用備忘録として。

| | コメント (0) | トラックバック (0)

ディレクトリ内EXCELファイル内容の一括検索

EXCEL / VBA / ファイル内検索

秀丸のGREPって便利だなーと前から思っていたのですが、今回ヘッダの一括変換とか該当シートの一括削除とかやっていて、どうもEXCELファイル内容の検索も出来そうだと思って作ってみました。

……Setがどういう働きのものなのか分かってなくて(多分基本中の基本)お陰で(多分)ちょーケアレスミスに気付かず昨日は終電帰りでしたが。出来たので本望です。納品前に使おうっと。

本当は検索結果を表示していく部分も変数で設定した方が良かったんでしょうがベタでやっちゃってます。大した修正じゃないんだろうけど今はこれにて。

Private Sub CommandButton2_Click()
    '================================
    ' ディレクトリ内の全ブックをループ
    '================================
    Dim myPath As String
    Dim myFName As String
    Dim myHeader As String
    Dim myOriginalBook As Workbook
    Dim mySelectSheet As Worksheet
    Dim myResultCellNumber As Integer

    Set myOriginalBook = ActiveWorkbook
'    Set myOriginalBook = Workbooks("3.01.003.99変換テスト.xls")
'    myOriginalBook.Activate
   
    myResultCellNumber = 5
   
    ' 検索対象文字列を取得
    myHeader = Worksheets(1).Range("SEARCH_STR").Value
   
    ' パスを取得
    myPath = ActiveWorkbook.Path
    ' 自ファイルが存在しているディレクトリをカレントディレクトリに設定
    ChDir myPath
    myFName = Dir("*.xls")
    ' ファイルがなくなるまで検索
    Do Until myFName = ""
       
        If Not (myOriginalBook.Name = myFName) Then
            ' ファイルOPEN
            Workbooks.Open Filename:=myFName
   
            '================================
            ' 検索
            '================================
            Dim MySheet As Sheets
            Dim SCount As Integer
            Dim myFoundCell As Range
            Dim myFoundCellLoop As Range
   
            Set MySheet = ActiveWorkbook.Sheets
            SCount = MySheet.Count
            ' 全ワークシートをループ
            For mycount = 1 To SCount
                ' mycount件めのシートをアクティブにする
                Set mySelectSheet = Worksheets(mycount)
                mySelectSheet.Activate
               
                Set myFoundCell = mySelectSheet.Cells.Find( _
                                                What:="rcvo", _
                                                After:=Range("A1"), _
                                                LookIn:=xlFormulas, _
                                                LookAt:=xlPart, _
                                                SearchOrder:=xlByRows, _
                                                SearchDirection:=xlNext, _
                                                MatchCase:=False, _
                                                MatchByte:=False, _
                                                SearchFormat:=False)
               
               
                ' 1件めの検索結果が存在した場合
                If Not (myFoundCell Is Nothing) Then
                    myFoundCell.Activate
                   
                    Dim myFirstCell As String
                    myFirstCell = myFoundCell.Address
                   
                    myOriginalBook.Worksheets(1).Range("A" & myResultCellNumber).Value = ActiveWorkbook.Name
                    myOriginalBook.Worksheets(1).Range("B" & myResultCellNumber).Value = mySelectSheet.Name
                    myOriginalBook.Worksheets(1).Range("C" & myResultCellNumber).Value = myFoundCell.Address
                    myOriginalBook.Worksheets(1).Range("D" & myResultCellNumber).Value = myFoundCell.Value
                    myResultCellNumber = myResultCellNumber + 1

                    ' 以降、検索を継続
                    Set myFoundCellLoop = mySelectSheet.Cells.FindNext(After:=myFoundCell)
                    myFoundCellLoop.Activate

                    Do While Not myFirstCell = myFoundCellLoop.Address
                        myOriginalBook.Worksheets(1).Range("A" & myResultCellNumber).Value = ActiveWorkbook.Name
                        myOriginalBook.Worksheets(1).Range("B" & myResultCellNumber).Value = mySelectSheet.Name
                        myOriginalBook.Worksheets(1).Range("C" & myResultCellNumber).Value = myFoundCellLoop.Address
                        myOriginalBook.Worksheets(1).Range("D" & myResultCellNumber).Value = myFoundCellLoop.Value
                        myResultCellNumber = myResultCellNumber + 1

                        Set myFoundCellLoop = mySelectSheet.Cells.FindNext(After:=myFoundCellLoop)
                        myFoundCellLoop.Activate
                    Loop
                End If
               
            Next mycount

            ' ファイルを保存せずCLOSE
            Workbooks(myFName).Close SaveChanges:=False
   
        End If
        ' 次のファイル名を設定
        myFName = Dir()
    Loop
End Sub

| | コメント (0) | トラックバック (0)

«ディレクトリ内EXCELファイルの対象シート削除