0

Bash で「ロギング支援」として使用する「ラッパー スクリプト」を開発しています。

呼び出し時のコール スタックに関する情報を出力する必要があります。

私はそれについて作業を行いましたが、いくつかの質問/疑問が残っており、ここの専門家からそれらについて可能な限り最良の回答を得たいと思います.


私のコード:

################################################################################
# Formats a logging message.                                                    

function my_function_format_logging_message() {                                 

  local -r TIMESTAMP="$(date '+%H:%M:%S')"                                      
  local -r PROCESS="$$" # Deliberately not using $BASHPID, focus: parent process

  local -r CALLER="${FUNCNAME[1]}"                                              

  local -i call_stack_position=1                                                
  if [[ "${CALLER}" == 'my_function_log_trace' ||                               
        "${CALLER}" == 'my_function_log_debug' ||                               
        "${CALLER}" == 'my_function_log_info' ||                                
        "${CALLER}" == 'my_function_log_warning' ||                             
        "${CALLER}" == 'my_function_log_error' ||                               
        "${CALLER}" == 'my_function_log_critical' ]]                            
  then                                                                          
    call_stack_position=$((call_stack_position++))                              
  fi                                                                            

  local -r SOURCE="$(basename "${BASH_SOURCE[$call_stack_position]}")"          
  local -r FUNCTION="${FUNCNAME[$call_stack_position]}"                         
  local -r LINE="${BASH_LINENO[$call_stack_position-1]}" # Previous function    

  local -r SEVERITY="$1"                                                        
  local -r MESSAGE="$2"                                                         

  # TODO: perform argument validation                                           

  printf '%s [PID %s] %s %s %s:%s - %s\n' \                                     
         "${TIMESTAMP}" \                                                       
         "${PROCESS}" \                                                         
         "${SEVERITY}" \                                                        
         "${SOURCE}" \                                                          
         "${FUNCTION}" \                                                        
         "${LINE}" \                                                            
         "${MESSAGE}"                                                           

}                                                                               
################################################################################

使用例:

my_function_format_logging_message CRITICAL Temporarily increasing energy level to 9001

また:

my_function_log_info Dropping back to power level 42

私の疑問:

  • call_stack_position=$((call_stack_position++))

この変数をインクリメントするより良い方法は考えられません。これのより良い/より読みやすい形式はありますか?

  • ロギング メソッドによって呼び出しが行われたかどうかを検出するために、より良い構造を使用できますか? (例: トレース、デバッグ、情報など)。これらのif発言はすべて私の目を痛めます。

  • 車輪の再発明/学習したいツールの誤用ですか? (つまり、シェルスクリプト)

確かに車輪の再発明かもしれませんが、これは自己訓練です.. ある日、料金所の夜勤をやめる.


ノート

指定された my_function_log_* 名に一致するものを探していますが、他にはありません。私がその程度の自由を持っていると仮定するのは良くありません (多くifの がまさにその理由でそこにあり、そのタイプの「セットメンバーシップ」テストを行うために、構文糖衣または言語機能のより良い使用を探しています)。

4

3 に答える 3

2

最初の 2 つの質問については、次のように提案できます。

if [[ "${CALLER}" == my_function_log_* ]]
then 
  let call_stack_position++
fi

log_ の後に一連の値が必要な場合:

if [[ "${CALLER}" =~ my_function_log_(trace|debug|info|warning|error|critical) ]]
then 
  let call_stack_position++
fi      
于 2013-03-15T01:12:42.350 に答える
1

Bashの型システムは、それを言いたければ、非常に初歩的なものです。文字列と整数はその唯一の第一級市民であり、配列は、PythonセットやRuby配列の機能にほど遠い後付けに取り組んでいます。inそうは言っても、文字列照合に依存する配列には貧弱な演算子があります。関数名の配列が与えられた場合:

log_functions=(my_function_log_trace my_function_log_debug my_function_log_info my_function_log_warning my_function_log_error my_function_log_critical)

これ:

[[ ${log_functions[*]} =~ \\b$CALLER\\b ]]

配列のメンバーのみに一致します。そして、貧乏人の構成について話しているので、上記のパターンをブール制御演算子と組み合わせて、貧乏人の三項代入に組み合わせて、数値評価を完全にスキップすることができます。

local -i call_stack_position=$([[ ${log_functions[*]} =~ \\b$CALLER\\b ]] && echo 1 || echo 2)

警告: GNU拡張機能をサポートしていないシステムregcomp()(特にOS XとCygwin)では、単語境界のマッチングでは、やや冗長な文字クラス形式を使用する必要があります。

[[ ${log_functions[*]} =~ [[:\<:]]$CALLER[[:\>:]] ]]

注:コードを見て、シェルスクリプトを学習していると言ったことに注意して、適切な質問とは関係のない2つの所見を提供します。

  1. 変数展開のブレース表記は、配列アクセス、展開操作、および文字列連結での変数名の曖昧性解消にのみ必要です。他の場合、つまりテストとprintfコマンドの両方では必要ありません。
  2. 拡張文字列操作の使用は、外部を使用するよりもはるかに高速であるため、可能な限り推奨されます。を使用する代わりに、をbasename使用して${var##*/}ください。
于 2013-03-15T04:04:26.917 に答える
1

インクリメントを行うより読みやすい方法は、数値コンテキストでインクリメントすることです。

(( call_stack_position++ ))

マッチングには、bash でグロブを使用できます。

[[ $CALLER == my_function_log_* ]]

車輪を再発明する限り、loggerコマンドを使用して bash から syslog ロギングを使用できます。ローカル syslog デーモンは、ログ メッセージのフォーマットとファイルへの書き込みを処理します。

logger -p local0.info "CRITICAL Temporarily increasing energy level to 9001"

コメントに基づいて更新します。連想配列を使用して、探しているものをより明確にすることができます。bash v4 以降が必要です。

declare -A arr=(
    ['my_function_log_trace']=1
    ['my_function_log_debug']=1
    ['my_function_log_info']=1
    ['my_function_log_warning']=1
    ['my_function_log_error']=1
    ['my_function_log_critical']=1
);

if [[ ${arr[CALLER]} ]]; then
    ...
fi

perreal の回答の正規表現と同様に、パターン マッチングに拡張グロビングを使用することもできますが、正規表現は使用しません。

shopt -s extglob
if [[ $CALLER == my_function_log_@(trace|debug|info|warning|error|critical) ]]; then
    ...
fi
于 2013-03-15T01:17:18.913 に答える