スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

開発者向け話題~自前logクラスについて

どうも。連投中のDUMAPICです。
さて、今回はAndroid開発者向けの話題です。

開発者の皆さんは、Androidでのログ出力はどのような形で実装されているのでしょうか?
ちなみに私は、APIで用意されているlogのラッパークラスを用意してログ出力制御を行っています。

なんでラッパークラスなんて作るの?と思われるかもしれませんが、一応自分のアプリで散々実績?を積んだソースコードを晒します。

このクラスを用意した理由は大きく2つあります。

(1) 開発中はログをだらだらと出力したいけどリリース時は出力させたくない。しかもデバッグだのリリースだのと一々ログをコメントアウトとかしたくない。
(2) logcatのフィルタを使いたいのでタグは統一化したいけど、やっぱりどのクラスでログ出力したかも把握したい。

ということで、オレオレクラスを作ったわけです。

<使い方>
・ログの出力有無は、static変数のIS_LOGGABLEで制御します。
あえてfinalにしていないのは、デバッグモード/リリースモード判定による真偽値を注入したいけど、モード取得にはContextが必要なため、クラス初期化子による初期化ができないと判断したためです。
ちなみにこれらのモード判定はAndroidManifest.xmlのandroid:debuggableの値をみて行います。具体的なやり方は他の方が公開していますので割愛しますw

・タグはstatic変数のTAG_NAMEに設定します。未設定の場合、ログ出力したクラス名をタグとして用います。 設定した場合は、ログ本文の冒頭に出力したクラス名を出力します。

<コーディング例>
Trace.TAG_NAME = "HogeHoge";
Trace.IS_LOGGABLE = DeployUtils.isDebuggable(this.getBaseContext());

Trace.log(Trace.Level.DEBUG, "[START] onCreate()");

とかかな。

もっといい方法あるよとか、おかしくね?とかありましたらコメントください。
ちなみにコーディングスタイルがちょっと変則的ですがそこはご愛嬌wでお願いします。

ではでは。

import java.util.Iterator;
import java.util.Map;

import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;

/**
 * 
 * ログ出力クラス。
 *
 */
public final class Trace
{
	public static final boolean IS_PRINTABLE_STACKTRACE = false;

	/** タグ */
	public static String TAG_NAME = null;
	/** ログ出力可否 */
	public static boolean IS_LOGGABLE = false;

	/**
	 * 
	 * ログの出力レベル列挙値
	 *
	 */
	public static final class Level
	{
		public static final int VERBOSE = android.util.Log.VERBOSE;
		public static final int DEBUG = android.util.Log.DEBUG;
		public static final int INFO = android.util.Log.INFO;
		public static final int WARN = android.util.Log.WARN;
		public static final int ERROR = android.util.Log.ERROR;
	}

	/**
	 * 
	 * ログを出力する。
	 * 
	 * @param level ログレベル(Level列挙値)
	 * @param tag ログのタグ
	 * @param msg ログ内容
	 * @param e 例外オブジェクト(null指定可)
	 */
	public static void log(
			final int level, 
			final String tag,
			final String msg,
			final Throwable e)
	{
		if(!IS_LOGGABLE) return;

		switch(level)
		{
			case Level.VERBOSE:
				if(e == null)
				{
					android.util.Log.v(tag, msg);
				}
				else
				{
					android.util.Log.v(tag, msg, e);
				}
				break;

			case Level.DEBUG:
				if(e == null)
				{
					android.util.Log.d(tag, msg);
				}
				else
				{
					android.util.Log.d(tag, msg, e);
				}
				break;

			case Level.INFO:
				if(e == null)
				{
					android.util.Log.i(tag, msg);
				}
				else
				{
					android.util.Log.i(tag, msg, e);
				}
				break;

			case Level.WARN:
				if(e == null)
				{
					android.util.Log.w(tag, msg);
				}
				else
				{
					android.util.Log.w(tag, msg, e);
				}
				break;

			case Level.ERROR:
				if(e == null)
				{
					android.util.Log.e(tag, msg);
				}
				else
				{
					android.util.Log.e(tag, msg, e);
				}
				break;

			default:
				break;
		}

		if(e != null && IS_PRINTABLE_STACKTRACE)
		{
			e.printStackTrace(System.out);
		}
	}

	/**
	 * 
	 * ログを出力する。
	 * 
	 * @param level ログレベル(Level列挙値)
	 * @param tag ログのタグ
	 * @param msg ログ内容
	 */
	public static void log(
			final int level, 
			final String tag,
			final String msg)
	{
		if(!IS_LOGGABLE) return;

		log(level, tag, msg, null);
	}

	/**
	 * 
	 * ログを出力する。
	 * 
	 * @param level ログレベル(Level列挙値)
	 * @param msg ログ内容
	 * @param e 例外オブジェクト(null指定可)
	 */
	public static void log(
			final int level, 
			final String msg,
			final Throwable e)
	{
		if(!IS_LOGGABLE) return;

		String occured = new Throwable().getStackTrace()[1].getClassName();
		occured = occured.substring(occured.lastIndexOf('.') + 1);
		log(level, occured, msg, e);
	}

	/**
	 * 
	 * ログを出力する。
	 * 
	 * @param level ログレベル(Level列挙値)
	 * @param msg ログ内容
	 */
	public static void log(
			final int level, 
			final String msg)
	{
		if(!IS_LOGGABLE) return;

		String occured = new Throwable().getStackTrace()[1].getClassName();
		occured = occured.substring(occured.lastIndexOf('.') + 1);
		if(TAG_NAME != null)
		{
			log(level, TAG_NAME, occured+" >>> "+msg, null);
		}
		else
		{
			log(level, occured, msg, null);
		}
	}

	/**
	 * 
	 * 環境設定の内容をデバッグレベルでログ出力する。
	 * 
	 * @param context コンテキスト
	 */
	public static void dumpSharedPreferences(Context context)
	{
		if(!IS_LOGGABLE) return;

		String occured = new Throwable().getStackTrace()[1].getClassName();
		occured = occured.substring(occured.lastIndexOf('.') + 1);

		SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(context);
		Map values = pref.getAll();
		Iterator keys = values.keySet().iterator();

		if(TAG_NAME != null)
		{
			log(Level.DEBUG, TAG_NAME, occured+" >>> "+"[DUMP] SharedPreferences", null);
			while(keys.hasNext())
			{
				String key = keys.next();
				String value = StringUtils.defaultIfNull(values.get(key), "null");
				log(Level.DEBUG, TAG_NAME, occured+" >>> "+key+" --> "+value);
			}
		}
		else
		{
			log(Level.DEBUG, occured, "[DUMP] SharedPreferences", null);
			while(keys.hasNext())
			{
				String key = keys.next();
				String value = StringUtils.defaultIfNull(values.get(key), "null");
				log(Level.DEBUG, occured, "  >> "+key+" --> "+value);
			}
		}
	}
}

テーマ : ソフトウェア開発
ジャンル : コンピュータ

tag : Android 開発者向け

コメント

非公開コメント

管理人のみ閲覧できます

このコメントは管理人のみ閲覧できます

管理人のみ閲覧できます

このコメントは管理人のみ閲覧できます

Re: アンドロイドアプリ

どうもです、DUMAPICです。
返事が遅れてすみませんでした。

ご質問の件ですが、技術的な話に限って言えば可能だと思います。
ただ、対象とするデータの種類は限定されると思いますけど。。。
いろいろな条件を加味しないと満足に動作はしないと思いますので、
時間と労力をかけた割には・・・という結果になりそうな予感がします。
相場的なものは・・・分かりませんw。ごめんなさい。
少なくとも私は(時間的な意味でも)できそうもありません。

Androidではやはりクラウドサービスを使うのがベターだと思います。
ではでは。

Re: 隠しコマンドについて

どうもです、DUMAPICです。

ご質問の件、私にも分からない部分が多くお役に立てそうもありません。
ごめんなさい。

ここからは想像になりますが、ご質問のところは恐らくInternalな部分かと思われます。すなわち端末に依存する部分ではないかと。。。で、この仮説が正しいとすると、十中八九root権限が必要になる可能性があります。
しかし、spare partsというアプリもありますので、もしかしたらAPIがあるのかもしれません。
一度同アプリの動きを検証してみるのもいいかもしれません(既に実施済みかと思いますけど。。。)

お力になれず申し訳ないです。
ではでは。
プロフィール

DUMAPIC

Author:DUMAPIC
FC2ブログへようこそ!

最新記事
最新コメント
最新トラックバック
月別アーカイブ
カテゴリ
検索フォーム
RSSリンクの表示
リンク
ブロとも申請フォーム

この人とブロともになる

QRコード
QRコード
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。