歴史的な理由から、オフィスには古いPanasonic TDA200 PBXがあります。 そして、ご存じのとおり、サーバー上の1つのプログラムが使用されたデータを読み取るために、シリアルポートへの呼び出しログを表示します。 このソフトウェアにはいくつかの制限があり、その使用が不便(ログファイルサイズ、データベースサイズ)になり、これらの欠点を克服するために、自然な怠inessさ(ログとデータベースの手動での定期的なクリーニングを避けるため)のために、独自のコードを作成することが決定されました。 そして、長い間、「パイソン」という言葉が目に付き、探究心が定期的に目覚めるので、このタスクをこの言語で、そして偶然にも私に馴染みのあるtclで実装することが決定されました。 さて、私は結果を社会と共有することにしました。 はい、すぐに問題が解決し、サービスが「産業」運用に移行したことに気付きます。 データストレージには、CentOS 7ホストシステムとしてMariaDB DBMSが使用されています(既に使用されています)。
そしてもう1つの発言-私からのpythonistは同じままなので、コードの品質を上げることはできますが、それほど多くはできません。 コード例はこの順序で与えられます。最初にpython、次にくすぐり、プロシージャとコマンドの説明は、スクリプトに記述されているのではなく、スクリプトの動作を理解するのに必要な順序になります。
Pythonimport pymysql import sys, os import re import datetime
Tcl package require mysqltcl # #set db(host) "host" #set db(user) "user" #set db(pass) "password" #set db(dbname) "ats_test" #set out_dir "~/tmp/ats"
ここでは、一般に、すべてが明確です-必要なモジュールをインポートし、変数を初期化します。 しかし、tclの例では、行はコメント化されています(これらの行は別のファイルに移動する必要があります。ネタバレをご覧ください)。理由は以下のとおりです。
config.tcl # set db(host) "host" set db(user) "user" set db(pass) "password" set db(dbname) "ats_test" set out_dir "~/tmp/ats"
スクリプトは、テキストファイルからのデータとシリアルポートからのデータを直接処理できます。このため、実行するキーがそれぞれ追加されます。-
port-ポートからの読み取り、
-file-ファイルからの読み取り:
if __name__ == "__main__": if len(sys.argv) > 2: if sys.argv[1] == '-port':
tcl-scriptには、別のオプション
-confが追加され 、コードは動作中のサーバーでテストされました。また、Pythonの他に、調整するためのくすぐりもありました。 そして、これによると、「すべてを含む」という原則に基づいて「実行可能ファイル」を構築する必要があり、設定の柔軟性を提供するために、このオプションが追加されました(さらに正確に)。
# if {[llength $argv] >= 2} { if {[lindex $argv 0] == "-conf"} { source [lindex $argv 1] } else { puts " " } if {[lindex $argv 2] == "-port"} { set port_name [lindex $argv 3] PortDataRead $port_name } if {[lindex $argv 2] == "-file"} { set log_file_name [lindex $argv 3] set log [open $log_file_name "r"] # if {[file isdirectory $out_dir] == 0} { file mkdir $out_dir } # while {[gets $log line] >= 0} { ParceString $line } close $log } } else { puts "\n :\n- \ \n # -conf config.tcl \n # tclsh logger.tcl -conf config.tcl -file TDA20013082015_12052016.lg\ \n- com- \ \n # tclsh logger.tcl -conf config.tcl -port /dev/ttyUSB0\n" exit }
続けましょう。 シリアルポート機能:
def port_data_read(port_name): global out_dir """ """ import serial ser = serial.Serial(port_name) ser.baudrate = 9600 while True:
tclでは、ファイルまたはポートの操作は同じです。 すなわち 最初に、いわゆるパイプ(パイプまたはチャネル)が
openコマンドで作成され、次にデータがこの「パイプ」から既に読み取られるか、ファイルまたはシリアルポートに関係なくそこに書き込まれます。
# proc PortDataRead {portName} { global fh # " " set fh [open $portName RDONLY] # fconfigure $fh -blocking 0 -buffering line -mode 9600,n,8,1 -translation crlf -eofchar {} # "" fileevent $fh readable Read vwait forever } # proc Read {} { global fh if {[gets $fh line] >= 0} { ParceString $line } }
チーム
fileevent $fh readable Read
チャンネルでイベントをハングアップするか、イベントへの反応を許可します。この場合、チャンネルにデータが表示されたら
読み取り手順を実行することを示しました。
それで、キーポイントに来ました-行を解析します。 ATSは、フィールドがスペースで区切られた行の形式でデータを「破棄」します。より正確には、各フィールドに文字のサイズが指定され、欠落したデータはスペースで実現されます。
30/09/16 10:44 501 01 <I> 0'00 00:00'13 D0
Python関数コード:
def parce_string(line): """ """
petとtickleの文字列関数にはいくつかの違いがあります。たとえば、
行[9:14]は9から始まり13文字を含む文字列の内容を返します。 右の境界線として、重要なシンボルに続くシンボルが示されています。 tclでは、コマンド
[string range $ line 9 13]がこの目的に使用されます。
proc ParceString {line} { global out_dir arrVariables # if {[string range $line 0 2] == "---" || $line == "" || [string range $line 3 6] == "Date"} { #puts $line return } # , # _ clock set fName [clock format [clock scan "now" -base [clock seconds]] -format %m_%Y] set out_log_name [file join $out_dir $fName] set out_log [open $out_log_name "a+"] puts $out_log "$line" close $out_log # # # "//" set arrVariables(call_date) "20[string range $line 6 7]\/[string range $line 3 4]\/[string range $line 0 1]" set arrVariables(call_time) [string range $line 9 13] set arrVariables(int_number) [string range $line 19 21] set arrVariables(ext_co_line) [string range $line 23 24] set arrVariables(dial_number) [string range $line 26 50] set arrVariables(ring) [string range $line 52 55] set arrVariables(call_duration) [string range $line 57 66] set arrVariables(acc_code) [string range $line 66 76] set arrVariables(call_code) [string range $line 77 81] # if {$arrVariables(dial_number) == "<I>"} { set arrVariables(call_direct) "In" set arrVariables(dial_number) "" } elseif {[string range $arrVariables(dial_number) 0 3] == "EXT"} { set arrVariables(call_direct) "Ext" set arrVariables(dial_number) [string range $arrVariables(dial_number) 3 end] } else { set arrVariables(call_direct) "Out" } InsertData
ティックルには変数の配列などの素晴らしいものがあります。この場合は
arrVariables()で、キーによって定義された対応する変数にすべてのデータを格納します。たとえば、
arrVariables(call_time) -これは呼び出しの時間です。 前の変数の例を使用すると、このすべてを「キーと値」リストのリストの形式で保存できます。これは次のようになります。
lappend lstVar [list call_time [string range $line 9 13]]
つまり リスト
lstVar (より正確には、リストを含む変数)で、2つの
call_time値のリストと、
9〜13文字の
$ line行の内容を追加します。
次に、データベースに行を追加します。その構造については以下で説明します。
テーブル構造CREATE TABLE `cdr` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`call_date` date DEFAULT NULL,
`call_time` time DEFAULT NULL,
`int_number` varchar(11) DEFAULT NULL,
`ext_co_line` char(2) DEFAULT NULL,
`dial_number` varchar(30) DEFAULT NULL,
`ring` varchar(5) DEFAULT NULL,
`call_duration` time DEFAULT NULL,
`acc_code` varchar(20) DEFAULT NULL,
`call_code` char(2) DEFAULT NULL,
`call_direct` varchar(45) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2775655 DEFAULT CHARSET=utf8 COMMENT='Call Data Records';
データベースへのクエリは、関数に渡されたパラメーターに基づいて動的に構築されます。 コードから、原則として、すべてが明確です-SQLクエリの要件に従って行をフォーマットし、適切な場所にコンマまたはブラケットを挿入します。 また、クエリは動的に構築されるため、一部の場所に余分なコンマとスペースが追加されますが、これらは
rstrip( '、')コマンドで削除する必要があります(もちろん、フィールドの数を数えて必要な数のコンマを追加できますが、オーバーヘッドは削減されません。そう)。 データは頻繁に投入されないため、データの各行(1つの要求)に対して1つのトランザクションが実行されます。 接続され、要求を満たし、切断されました。
そして、機能コード自体:
def insert(**kwargs): """ . """ qwery = 'INSERT INTO `cdr` (' for key in kwargs.keys(): qwery = "{} `{}`, ".format(qwery,key) qwery = qwery.rstrip(', ') + ') VALUES(' for key in kwargs.keys():
そして今、くすぐりで同じこと:
proc InsertData {} { global arrVariables db set qwery "INSERT INTO `cdr` (" # foreach key [array names arrVariables] { set qwery "$qwery `$key`, " } set qwery "[string trimright $qwery ", "]\) VALUES\(" foreach key [array names arrVariables] { set qwery "$qwery \"[string trim $arrVariables($key)]\"," } set qwery "[string trimright $qwery ", "]\);" puts $qwery # set conn [mysql::connect -host $db(host) -db $db(dbname) -user $db(user) -password $db(pass) -encoding utf-8] mysql::exec $conn $qwery mysql::commit $conn mysql::close $conn }
ここでストーリーを完成できます。 私の意見では、この特定のケースでは、どちらの言語も他の言語も利点はありません(私は少し違いますが、くすぐりは私にとってよりきれいですが、これは習慣によるものです)。 Pythonでの問題も発生しません。 ソースは、最新バージョンおよびWindows 10のCentosおよびFedoreでテストされました。プロジェクト(データ収集の観点から)は、論理的な結論に達し、運用されました。電話のディレクトリと収集されたデータのレポートを含む単純なWeb銃口がまだありますが、これは別の記事のトピックです。
ソースはここから入手できます:
Gitリポジトリ