MHAの動作確認と切替検証
...MHAの動作確認と切替検証
前回のつづきです。以下の図のように切り替わるようテストします。
※本検証はマスタ1台、スレーブ2台、マネージャ1台構成。(多段構成は中間ノード障害時の復旧が猥雑になるので回避)
スレーブにmanagerを同居させるとpurge_relay_logsとかぶると上手く切り替わらない可能性があるようです。
※2台しかない場合で上手く切り替わらないことがあるようです。以下参考。
http://heartbeats.jp/hbblog/2013/05/mysql-mha-haproxy.html⑥ 起動前チェック
・sshの動作チェック
[shell] # masterha_check_ssh –conf=/etc/app1.cnf [/shell] OKな場合最終的に以下のように出力される
[shell] Tue Oct 23 15:02:22 2012 - [info] All SSH connection tests passed successfully. [/shell]
・replicationの動作チェック
[shell] # masterha_check_repl –conf=/etc/app1.cnf [/shell] OKな場合最終的に以下のように出力される(※mysql5.6からはMHAのバージョンによってはbinlog-checksum=NONEにしないとここで失敗するかもしれません)
[shell] MySQL Replication Health is OK. [/shell] ※失敗するパターン
レプリケーションのフィルタリングルールが合っていない
LVSとMHAマネージャが相乗りの場合、チェックタイミングが重複しホスト毎DBサーバに拒否されてしまう(要flush hosts;)MHA(MasterHighAvailabilityManager)の導入設定
...MHA(MasterHighAvailabilityManager)の導入設定 使用バージョン:mha4mysql-manager-0.53-0、MySQL-5.5

①簡単な利点などの解説
MHAとはmysqlのマスタ障害時に最新のスレーブをマスタとして他のスレーブの差分を補完しマスタの向き先を変えてくれるプロダクト。
Heartbeat+mon+mysqlに比べるとreplicationの再構成も行ってくれるので切り替わってもDBがシングルにならないのが利点。(3台以上の構成の場合)作者のスライド
公式サイト
MHAの制約:mysql5.0以上、SBR(ステートメントベースレプリケーション)の場合LOAD DATA INFILEを使えない
※マネージャはadminサーバ、ノードはDBサーバ(マスタ・スレーブ共通)② マネージャにてインストール ※以下、admサーバから実施
・インストール
[php]wget http://mysql-master-ha.googlecode.com/files/mha4mysql-node-0.53-0.noarch.rpm
wget http://mysql-master-ha.googlecode.com/files/mha4mysql-manager-0.53-0.noarch.rpm
yum –enablerepo=rpmforge install \
perl-Config-Tiny \ perl-Time-HiRes \ perl-Log-Dispatch \ perl-Parallel-ForkManager \ perl-Params-Validate
yum install perl-DBD-MySQL
rpm -ivh mha4mysql*
[/php] 入ってなかったら
[shell]yum install –enablerepo=remi mysql mysql-server perl-DBD-MySQL[/shell] ※マネージャはmysql-serverいらないかも
③ ノードにてインストール ※以下、dbサーバから実施
[shell]DEVLABはNginx環境に移行しました
...2013年3月末週、DEVLABサイトの環境移管を人知れず行ってました。
今週の4/2頃まではDEVLABにアクセスした人の中には、サイトが表示されなかったり、不具合が起きていた人もいたかもしれませんが、それらはすべて環境移管に伴う余波としてご理解いただけますと幸いです。まぁ、DEVLABの存在意義と運営方針の一つとして、「インターネットに関わる技術の研究開発のためには恐れずに何でもやってみよう!」というコンセプトを持っているので、今後もISAO社のDEVLABに関わるエンジニアの「好奇心の趣くままに」「衝動的に」「たとえサイトが壊れるとしても」色々とやって行くので、もしサイト来た時に変な動きをしていても ―― お、今何かやっているのかな?――と、温かく見守っていただきたいです(単なるバグの可能性もありますが、それも含みで)。そんなこんなで、DEVLABの環境を今までのApache環境から今流行りのNginx環境に移管した次第。
さらに、noSQLデータベースの「MongoDB」やNode.jsもインストールして、今後は「リアルタイムWEBアプリケーション」の開発もできるように整備したのですが、これはISAO社のエンジニア向けの環境整備なので、DEVLAB側には今のところ影響はないかと。さて、巷では「Nginx+リバースプロクシ+WordPress」の構成でWordPressのサイトパフォーマンスが劇的に向上すると云われているので、早速本DEVLABでもその施策を実施してみました。
結果、1ページ単位での表示レスポンス(レイテンシー)は特に変化はなかった(単ページ単位だと、逆にレスポンスはApacheの方が勝ってました…が、体感速度的には変わらなかった)のだが、Jmeterで負荷テストしてみたら、多数の同時リクエストが発生した際のNginxのレスポンスはかなり驚異的な向上が見られた次第。
実際にDEVLABのTOPページのリクエストレスポンスを比較したら、Nginx環境ではApacheの約23倍ほどもレスポンスが向上しました。
いやぁ、Nginxスゴイ!という感想でした。ま、DEVLABは常時負荷が高まるほどアクセスされないので、今のところNginx環境も宝の持ち腐れ的な感があるんですけどね…。
Contact Form 7 でエラー時用画面にリダイレクトする方法
...Contact Form 7では、管理画面の、各フォームごとの編集画面の「その他の設定」に、
on_sent_ok: "window.location.href = 'リダイレクト先のURL';"と入力すれば、Contact Form 7 の処理終了後に、設定したURLにリダイレクトしてくれます。
しかし、この設定をすると、成功しても失敗しても同じURLに遷移するため、送信が成功したか失敗したかわかりません。
画面遷移ではなく、メッセージの表示をさせる場合では、成功時と失敗時でメッセージが切り替えられており、その処理にはJavaScriptを使っているはずです。
そこで、Contact Form 7 のjsファイルを改変して、エラー時にエラー時用のリダイレクトURLへ遷移させることにします。
/pm_webform/wp-content/plugins/contact-form-7/includes/js scripts.js
67行目付近の以下の行
} else {の下に以下の行を追加すると、失敗時用のリダイレクトURLへ遷移できます。
window.location.href = "失敗時用リダイレクトURL";同様に、57行目付近の以下の行
} else if (1 == data.mailSent) {の下に以下の行を追加すると、成功時用のリダイレクトURLへ遷移できます。
window.location.href = "成功時用リダイレクトURL";Contact Form DB でチェック処理
...Contact Form DB でテーブルへの insert を行う前に、何らかのチェック処理を入れたい場合、フックを使います。
function my_form_chk( $cf7 ) { // 入力フォームの値取得 foreach ($cf7->posted_data as $posted_name => $posted_value) { // 元の値は変えないため別変数へ $posted_name_2 = $posted_name; $posted_value_2 = $posted_value; // 値の整形 $posted_nameClean = stripslashes($posted_name_2); $posted_value_2 = is_array($posted_value_2) ? implode($posted_value_2, ', ') : $posted_value_2; $posted_valueClean = stripslashes($posted_value_2); // それぞれの変数に代入 if( $posted_nameClean == 'a' ) { $input_param_a = $posted_valueClean; } if( $posted_nameClean == 'b' ) { $input_param_b = $posted_valueClean; } if( $posted_nameClean == 'c' ) { $input_param_c = $posted_valueClean; } } // チェック処理 if ( $input_param_a !== $input_param_b || $input_param_a !== $input_param_c ) { $cf7->skip_mail = true; } } add_action('wpcf7_before_send_mail', 'my_form_chk', 1);上記の例では、入力フォームで a,b,c という3つの入力項目があり、その値を受け取って、a と b、または a と c が一致指定なければ $cf7->skip_mail に true を代入しています。
Contact Form DB のテーブルについて
...Contact Form 7 というアンケートフォームのプラグインは、メールを送信するだけなので、DBへデータを格納するようにするプラグインが Contact Form DB です。
両プラグインをWordPressに入れることで、手軽に入力フォームの内容をDBに格納できます。
しかし、この Contact Form DB で作られるテーブルが曲者でした。
WordPressの管理画面から Contact Form DB の管理画面を表示すると、入力フォームから入力されたデータの一覧を表示でき、それを見るとあたかも一つのフォームからの投稿が一つのレコードとして格納されているように見えます。 しかし、実際のテーブルには、入力フォームの input 一つ一つがそれぞれ1レコードとして登録されます。
入力項目が3つのフォームだと、1回の投稿で3つレコードが登録されるわけで、それぞれのレコードには、それぞれの入力項目の内容のみが、投稿時間と入力フォーム名と入力項目名をキーに記録されるのです。
ちなみにテーブル構造は下記の通り。
mysql> DESC wp_cf7dbplugin_submits; +-------------+---------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------------+---------------+------+-----+---------+-------+ | submit_time | decimal(16,4) | NO | MUL | NULL | | | form_name | varchar(127) | YES | MUL | NULL | | | field_name | varchar(127) | YES | MUL | NULL | | | field_value | longtext | YES | | NULL | | | field_order | int(11) | YES | | NULL | | | file | longblob | YES | | NULL | | +-------------+---------------+------+-----+---------+-------+ 6 rows in set (0.03 sec)インデックス一覧は下記の通り。
iPhoneやiPadで撮影した画像を他のデバイスで見ると自動で回転してしまう場合の対処法
....iphone { position: relative; height: 123.75px; width: 62.5px; border-radius: 8.75px; margin: 12.5px auto; background: -webkit-linear-gradient(-165deg, rgba(255,255,255,0.4), rgba(255,255,255,0.15) 35%, transparent 35%), -webkit-linear-gradient(top, transparent 21.25px, #222222 21.25px, #151515 102.5px, transparent 102.5px), -webkit-linear-gradient(top, #000, #0a0a0a); background-repeat: no-repeat; background-size: 100% 100%, 55px 100%, 100% 100%; background-position: 0 0, 3.75px 0, 0 0; box-shadow: 0 0 0 0.75px black, -10px -32px 0 -30.75px black, 0 0 0 1.25px #a09f9d, 12.25px -32.5px 0.75px -30.75px #777, 11.5px -32.5px 0.5px -30.75px #ddd, 15.5px -27.75px 0 -26.25px #8e8d8b, 15.5px -28px 0 -26.25px #b4b3b1, 15.5px -28.25px 0 -26.25px #666; } .iphone:after { content: ‘▢’; line-height: 11.5px; text-align: center; font-size: 7px; color: #666; position: absolute; width: 11.5px; height: 11.5px; border-radius: 50%; background: white; bottom: 4.5px; left: 25px; border: 0.5px solid #0a0a0a; background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.85), black); box-shadow: -9.75px -102.5px 0 -5.75px #000f31, -9.75px -102.5px 0 -5.5px #0a1c5a, -10px -102.5px 0 -5.25px #0d1216, -10px -102.5px 0 -4.75px #1b191a, -3px -102.5px 0 -5.5px #333, -2px -102.5px 0 -5.5px #333, -1px -102.5px 0 -5.5px #333, -0px -102.5px 0 -5.5px #333, 1px -102.5px 0 -5.5px #333, 2px -102.5px 0 -5.5px #333, 3px -102.5px 0 -5.5px #333, 4px -102.5px 0 -5.5px #333, 5px -102.5px 0 -5.5px #333, 6px -102.5px 0 -5.5px #333, -3px -102.5px 0 -4.5px #0a0a0a, -2.25px -102.5px 0 -4.5px #0a0a0a, -1.5px -102.5px 0 -4.5px #0a0a0a, -0.75px -102.5px 0 -4.5px #0a0a0a, 0px -102.5px 0 -4.5px #0a0a0a, 0.75px -102.5px 0 -4.5px #0a0a0a, 1.5px -102.5px 0 -4.5px #0a0a0a, 2.25px -102.5px 0 -4.5px #0a0a0a, 3px -102.5px 0 -4.5px #0a0a0a, 3.75px -102.5px 0 -4.5px #0a0a0a, 4.5px -102.5px 0 -4.5px #0a0a0a, 5.25px -102.5px 0 -4.5px #0a0a0a, 6px -102.5px 0 -4.5px #0a0a0a; } .iphone:before { position: absolute; content: ‘’; width: 0.5px; height: 29.25px; background: transparent; top: 10px; left: -1.75px; background-image: -webkit-linear-gradient(left, transparent 0px, transparent 0.25px, #7a7879 0.5px), -webkit-linear-gradient(top, #383838 0.25px, #b9b9b9 0.75px, #b9b9b9 2.5px, #383838 4.75px, #b9b9b9 5.75px, transparent 5.75px, transparent 13.25px, #383838 13.25px, #b9b9b9 13.5px, #dadada 14.5px, #383838 15.5px, black 15.5px, black 16.5px, #383838 16.5px, #b9b9b9 16.75px, #dadada 17px, #383838 17.5px, transparent 17.5px, transparent 25px, #383838 25px, #b9b9b9 25.25px, #dadada 26.25px, #383838 27.25px, black 27.25px, black 28.25px, #383838 28.25px, #b9b9b9 28.5px, #dadada 28.75px, #383838 29.25px); } .display { position: absolute; top: 21.75px; left: 2px; width: 56px; height: 80px; margin: 0; padding: auto; background: #fafafa; border: solid 1px #afafaf; font-size: 24px; font-weight: bold; line-height: 78px; text-align: center; vertical-align: middle; } .rotate_90deg { -moz-transform: rotateZ(90deg); -webkit-transform: rotateZ(90deg); -o-transform: rotateZ(90deg); } .rotate_180deg { -moz-transform: rotateZ(180deg); -webkit-transform: rotateZ(180deg); -o-transform: rotateZ(180deg); } .rotate_270deg { -moz-transform: rotateZ(270deg); -webkit-transform: rotateZ(270deg); -o-transform: rotateZ(270deg); } .device_deg_list { margin: 1em auto 2em; padding: 0; background: #ffffff; border: solid 1px #999999; } .device_deg_list th { padding: 2px; background: #d0d0d0; font-weight: bold; } .device_deg_list td { text-align: center; vertical-align: middle; } .device_deg_list td.odd { background: #f0f0f0; } .device_deg_list td.visual { width: 160px; text-align: center; vertical-align: middle; } .device_deg_list td.orientation { min-width: 120px; } .device_deg_list td.resampling { min-width: 200px; } .exif-value{ clear: both; display: block; font-size: 9px; color: #808080; }
PATH_INFOを取得してhiddenに代入
...URLにパラメータをくっつけて、GETで送信する場合、
http://www.example.com/?param0=aaa¶m1=bbbという感じで渡して、受け取るときは
$param0 = $_GET['param0']; $param1 = $_GET['param1'];または
$param0 = $_REQUEST['param0']; $param1 = $_REQUEST['param1'];というようにするのが一般的ですが、以下のように、
http://www.example.com/aaa/bbb/で値を渡して、受け取りは
$param = split("[/\.]", $_SERVER["PATH_INFO"]);とすると、$param[0] に「aaa」が、$param[1] に「bbb」が代入されます。
さて、これを WordPress でやろうとすると、「aaa」とか「bbb」をURLとして処理しようとしてしまい、当然パーマリンクや実体があるわけではないので、表示できません(実体があればそちらを表示しちゃう)。
WordPress では PATH_INFO を使わない方がよさそうなのですが、使わざるを得ない場合、WordPress とは関係なく、一旦 PATH_INFO を受けるプログラムを作成し、そこから何かしらの方法で WordPress にパラメータを渡すようにします。
受け方は上記の通りなので、あとは渡し方になるのですが、手軽なのは GET でリダイレクトする方法でしょう。
$url = "遷移先URL?param0=" . $param0 . "¶m1=" . $param1; header("HTTP/1.1 301 Moved Permanently"); header("Location: " . $url );GETではURLにパラメータが見えるということであれば、セッションを使う方法もある。
wp_insert_attachment() で新規 insert
...wp_insert_attachment() のリファレンスには、
wp_insert_attachment( $attachment, $filename, $parent_post_id );と書かれており、$parent_post_id を指定する必要があります。つまり、事前に posts テーブルに何らか insert して、そのレコードの post_id を指定することとなります。
でも、新規で画像情報を登録したくて、でも紐づく投稿がまだ無い場合、post_id が無いわけで、どうするべきか調べてみました。
WPのソースを追ってみて、実際に試してみたところ、
wp_insert_attachment( $attachment, $filename, 0 );というように、$parent_post_id = 0 とすることで、新規で insert されます。
ちなみに、$attachment には、
$wp_filetype = wp_check_filetype(basename($filename), null ); $wp_upload_dir = wp_upload_dir(); $attachment = array( 'guid' => $wp_upload_dir['url'] . '/' . basename( $filename ), 'post_mime_type' => $wp_filetype['type'], 'post_title' => preg_replace('/\.[^.]+$/', '', basename($filename)), 'post_content' => '', 'post_status' => 'inherit' );という感じで事前にアップロードしておいた画像の画像情報を入れてやればOK。
スクリプトで WordPress の DB にアクセスしたい
...WordPress の DB にスクリプトからアクセスしたい場合、単純に MySQL にアクセスして処理すればいいのですが、何らかの理由で WordPress の関数を使いたい場合(画像の投稿をスクリプトで行う等)は、
require_once('wp-blog-header.php');でOKなのですが、一部のメソッドは直接そのメソッドが記述されたソースをインクルードする必要があります。
例えば、カテゴリ登録するための wp_insert_category() を使いたい場合、
require_once('/wp-admin/includes/taxonomy.php');とする必要があります。/wp-admin/includes/にクラスがあるので必要なものを探しだして、インクルードします。
また、wp-blog-header.phpをインクルードするということは、例えば、HTTPSで必ずアクセスさせたり、ログインユーザのみに見せるといったようなWebの制限をfunction.phpなどに入れて、サイト全体に制限かけた場合、影響を受けます。
そこで、そういった制限を入れた場合は、その制限処理に、
if ( ! preg_match( '/^(script.php|hogehoge.*.php)/', basename( $_SERVER['SCRIPT_NAME'] ) ) ){ // 制限処理 }のように除外したいスクリプト名(上記の場合、「script.php」か「hogehoge.*.php」にマッチするスクリプト)を指定して、処理から除外する必要があります。
これをしない場合、スクリプトを実行すると、制限に引っかかり、処理が止まります。
複数ファイルのアーカイブをダウンロードさせる時の方法
...例えば、複数個の画像ファイルをまとめてダウンロードさせたりする場合、サーバ上でテンポラリディレクトリに画像ファイルをコピーして、それらをアーカイブしてダウンロードさせたりします。 しかし、これだと画像ファイルをいちいちコピーすることになるので、ストレージを圧迫する可能性があるし、ファイル数が多いとコピーに時間がかかります。
そこで、シンボリックリンクを作成し、そのディレクトリ毎アーカイブすることにします。
まず、テンポラリディレクトリを作成します。
$tmp_path = "/tmp/" . uniqid(rand()); $archive_dir = "(指定したいディレクトリ名)"; $tmp_dir = $tmp_path . "/" . $archive_dir;テンポラリディレクトリまでのパスと、テンポラリディレクトリ名を分けている理由は後述。
次に、作成したテンポラリディレクトリに、画像ファイルのシンボリックリンクを作成します。
// $filelists:画像ファイル名のリスト // $$image_dir:画像ファイルの格納ディレクトリ foreach( $filelists as $image_name ) : $target = $image_dir . "/" . $img_name; $link = $tmp_dir . "/" . $img_name; symlink($target, $link); }あとは、このテンポラリディレクトリごとアーカイブします。特に画像ファイルの場合、圧縮してもサイズは余り変わらないので、tar でアーカイブすれば、圧縮処理が無い分、処理が早いです。 tarコマンドのオプションで「h」をつけることで、シンボリックリンクを実体としてアーカイブできます。これがキモですね。
// アーカイブファイルパスを設定 $tar_file = tempnam("/tmp", "DOWNLOAD"); // tarコマンドでアーカイブ $command = "tar chf $tar_file -C $tmp_path $archive_dir"; system( $command );この時、tarコマンドのオプションで「-C」をつける。これで、指定したディレクトリに移動してから処理します。 こうすることで、テンポラリディレクトリのフルパスでアーカイブされずに済みます。
パスワード管理アプリ(Android版)
...パスワードは使い回してはいけない。パスワードは一定の文字数以上でなければならない。パスワードは定期的に変更しなければならない…そんなの覚えるの無理でしょ!
というわけで、社内向けに作成したパスワード管理アプリを公開します。
既に山ほどのパスワード管理アプリがgoogle playで絶賛公開中ですが、それらのアプリを採用しなかった理由は
- (社内用としては)不要な権限を要求するアプリが多い
- 必要な機能がない
- マルウェアをつかんでしまう可能性がある
といったためです。
今回作成したアプリの特徴は
- ランダムパスワード自動生成機能搭載
- 要求する権限はSDカード読み書きのみ(バックアップのため)
- 2ヶ月以上更新していないパスワードを警告
- 充実したソート機能
- マッシュルーム対応
- マッシュルーム対応していないIME向けに、クリップボードコピーも対応
- Android 4系のカッコイイUIを2.2以上にご提供
- マルウェアではない(自己申告になりますが…)
ぜひお試し下さい。
インストール方法:
- [設定] > [アプリケーション] > [不明な提供元]チェックボックスをON
- 以下のリンクをクリックしてapkをダウンロード
- インストールする
jQuery 1.9 で変更された仕様によって動かなくなるプラグインが多い
...code { padding: 2px; background-color: #f4f4f4; color: #7f0055; font-weight: bold; border: solid 1px #ddd; } blockquote { margin-left: 1em; font-size: 12px; line-height: 17px; background-color: #fdfdfd; border: solid 1px #ccc; padding: 4px; font-style: normal; }
現在開発しているあるシステムで、最新のjQuery 1.9.1を導入して開発を行っていたところ、先月開発していたシステムでは動いていて、同じように実装したはずなのに動かないjQueryプラグインがあってハマりました。それがWordPressのコアに同梱されている「thickbox」でして、管理パネルでは動いて、テーマ側で動かないのは何故だろうと思って調べてみたところ、読み込んでいるコアのjQueryが1.8系と1.9系と差があった。もしや・・・と思って、jQuery 1.9系の仕様変更内容を調べてみたら、おっと、今までかなり重宝していたメソッドがなくなっているではありませんか。
将来的に削除されることは知っていたけど、使い勝手が良くて使っていた$.browser()と、何気に動的に生成されたDOMオブジェクトに対して適応性が低い$.bind()より汎用的に使えるため重宝していた$.live()などが削除されてしまったため、これらのメソッドを使っているjQueryプラグインではエラーが発生してしまうようになってしまいました。
・・・と言うことで、jQuery 1.9系での主な仕様変更をまとめてみた。$.browser()が廃止1.3からサポート外に指定されてましたが、ついにメソッドが削除されてしまった・・・何気にお手軽にブラウザ判定できるので使い勝手良かったんだが・・・致し方ないですね。これからは、$.support()を使って判定式を組まないといかんです。$.live()が廃止$.bind()の拡張版メソッドで、bindはjQueryやJavaScriptで動的に生成されたオブジェクトに対して処理をバインドできなかったのを可能にするメソッド。これも使い勝手が良くて重宝していたのだが・・・廃止されてしまった。今後は$.on()と$.off()を使えってことです。まぁ、バインドイベントのオン・オフを判り易く制御できるのでこちらの方が確かにスマートだ。$.die()が廃止上記live関数を削除するメソッドです。liveがなければこちらも不要ということですね。
$.sub()が廃止プロパティとメソッドが自由に変更可能なコアjQueryオブジェクトのコピーを作成するメソッドです。プラグイン開発などで、コアを変更せずに、独自にjQueryコアを拡張する時などに使われていましたが、結構巨大なjQueryコア自体をコピーしてメモリ食いまくってまで作るプラグインもないだろう・・・という判断があったのかも。まぁ、プラグイン開発者以外にはあまり使わないメソッドだし、1.8系からこのメソッド自体がプラグイン化されたらしいので、廃止によるインパクトは低いかな。
$.toggle(fn1(),fn2(),[...fnN()])の廃止1.7系で非推奨化されてたメソッドです。指定のオブジェクトがクリックされる毎にfn1、fn2、・・・fnNと関数を実行して、fnN以降はfn1に戻るみたいな処理が書けるメソッドでした。まぁ、クリック毎にそこまで処理変えなきゃいかんUIってどうよ?って感じなので、廃止は妥当かな・・・と。あ、ちなみに、関数バインド型ではないイベントエフェクト型の
$.toggle()は廃止されていません。他に記述順や処理内容が変更されたメソッド
$.add()、$.before()、$.after()、$.addSelf()などなど細かいところが色々と変わっているようです。
AndroidのLogCatのTagにクラス名、メソッド名、行番号を表示するクラス
...たとえデバッカがあってステップ実行が出来ようとも、デバックログの手軽さは手放せません。Androidの場合、標準のLogクラスを使えば、その目的を達成できるのですが、できたらTagに、クラス名、メソッド名、行番号が出たら嬉しいと思う人が多いはず!
と思ってぐぐってみたら、実現している方がいました。
[
AndroidのLogCatのTagで「クラス名.メソッド名:行番号」と表示するには?
](http://kinsentansa.blogspot.jp/2012/06/androidlogcattag.html)
せっかくなんで、これを即使えるようにクラス化してみました。
[code lang=“java” light=“true”] package jp.fuga.hoge.android.app;
import java.util.regex.Pattern; import jp.fuga.hoge.android.app.BuildConfig; import android.util.Log;
/** * ログ出力クラス。
* ログを出力する場合には必ず本クラスを使用すること。
* リリース時には、デバックログを出力しないよう設定される。 * */ public class L {/** * デバック用ログを出力する。 本番リリース時は出力されない。 * * @param msg 出力するメッセージ */ public static void d(String msg) { if (!BuildConfig.DEBUG) return; Log.d(getTag(), msg); } /** * エラー用ログを出力する。 <br> * catchの中や想定外の動作でログを出力する場合に使用すること。<br> * 本番リリース時も、起きたエラーを解析するために本ログは出力される想定。 * * @param msg 出力するメッセージ */ public static void e(String msg) { Log.e(getTag(), msg); } /** * 同上 * * @param msg * @param t */ public static void e(String msg, Throwable t) { Log.e(getTag(), msg, t); } /** * タグを生成する * * @return className#methodName:line */ private static String getTag() { final StackTraceElement trace = Thread.currentThread().getStackTrace()[4]; final String cla = trace.getClassName(); Pattern pattern = Pattern.compile("[\\.]+"); final String[] splitedStr = pattern.split(cla); final String simpleClass = splitedStr[splitedStr.length - 1]; final String mthd = trace.getMethodName(); final int line = trace.getLineNumber(); final String tag = simpleClass + "#" + mthd + ":" + line; return tag; }}