ソフトウェアの動作がわからない場合の対処方法



出所



また、どのように機能するかわからないソフトウェアも好きではありません。 プログラムがブラックボックスの場合、すべての理解できない状況に対して、正確に2つのオプションがあります。プランテインを添付するか、製造元に問い合わせてください。 しかし、第一に、オオバコがどこまで成長するかはわかりません。第二に、ベンダーにさまざまな詳細を問い合わせることも、どういうわけか地獄ではありません。



数年前、顧客の1人がまったく同じソフトウェアを見つけました。入力でのリクエスト、出力での回答ですが、内部では何が明確ではありません。 自動銀行システムまたはABSと呼ばれます。 ただし、基本的には、処理からの要求を処理して結果を返すデータベースです。 その結果、答えは次のとおりです。銀行がこの操作を実行できるかどうか。 アーキテクチャ上の制限により、外部クエリを使用してこのデータベースにアプローチする方法はありません。 最近のプロジェクトで、彼らは再び小売業で同じソフトウェアに直面し、彼らのベストプラクティスをすでに共有する時だと考えました。



以前の記事で、トラフィックを聞くことがTechnoservのクライアントの1つが内部ソフトウェアの問題を見つけるのにどのように役立つかについて話しました。 これは、その長年の課題の技術的な分析であり(最終的には覚えています)、最終的には、このタイプの監視の2つの重要な利点になります。



トラフィック分析用の特別な製品MicroFocus RUM(前の記事の上のリンクを参照)は、もちろん、さまざまなネットワークプロトコルをサポートしていますが、これらはまさに必要なものです-いいえ。 また、内部銀行システムからABSへのRPCサービス要求と、外部デバイス(ATMおよびPOS端末)から同じABSへのISO8583プロトコルを使用したトラフィックをリッスンする必要がありました。



RPCデータの分析



顧客からの問題の声明は次のように見えました。



「皆さん、分析するのに数時間のトラフィックがあります。 ここでは、異なる銀行システムからABSへのリクエスト-レスポンスの形でのトランザクションがあります。 そのような各リクエストの実行時間を知り、いくつかのフィールドの値を取得し、エラーの数を数える必要があります。 出力には表レポートが必要です。」



このタスクで最も難しかったのは、受信したトラフィックの分析です。 シーケンスを見つけ、フローを個別のトランザクションに分割するには、骨の折れる作業が必要でした。 分析後、各トランザクションは、要求と応答、および他のフィールドのセットに対して同じ識別子を持つXMLパッケージであることが判明しました。 スクリーンショットは、Wiresharkインターフェイスと対応するXMLでのこのトラフィックの例を示しています。







RUMがさまざまな種類のネットワークデータを理解できるようにするには、このデータを説明する必要があります。 これを行うために、C ++でスクリプトを開発しました。 以下は、RPCトラフィックを解析するためのコードです。



トラフィック解析コード
#include "./ProtocolRPCRQ.hpp" #include <stdlib.h> #include <stdio.h> #include <signal.h> #include <setjmp.h> #include <iostream> #include <fstream> #include <base/ProtocolConfig.hpp> #include <base/ProcessingState.hpp> #include <utils/LogHelper.hpp> using namespace rum::public_sdk; sigjmp_buf mark; void segfault_sigaction(int signal) { ; } RPCRQProcessor::RPCRQProcessor( const char* name, IProtocolProcessor* next ) : ProtocolProcessorBase( name, next, "protocols.RPCRQProcessor" ) { } void RPCRQProcessor::initialize( const ProtocolConfig& config ) { ; } /*override*/ void RPCRQProcessor::process( ProtocolEvent& event, ProcessingState& ps, ProcessingMode mode ) { bool isParsed; try { if (mode != PROCESSING_FULL ) { forwardToNextProcessor( event, ps, mode); return; } EventParsingContext eventContext( event ); isParsed = doAllParsingWork( ps.getRequest(), ps.getResponse(), eventContext); if (isParsed) { forwardToNextProcessor(event, ps, mode); } else return; } catch (...) { LOG4PROBE_ERROR( getDefaultLogger(), "logger1"); } } String RPCRQProcessor::search_substring(String data, String start, String stop) { String empty = ""; try { size_t start_pos = data.find(start); if (start_pos!=std::string::npos) data = data.substr(start_pos+start.length()); size_t stop_pos = data.find(stop); if (stop_pos!=std::string::npos) data = data.substr(0,stop_pos); if (data.find("xmlns")!=std::string::npos) return empty; if ((start_pos==std::string::npos) || (stop_pos==std::string::npos)) return empty; else return data; } catch (...) {return empty;} } String RPCRQProcessor::stream_to_string(DataStream& stream,int offset) { String rumstring = ""; String empty = ""; int i = 0; try { while ( (!stream.eof()) && (i<10000)) { i++; if (stream.peek()!=0xff) { unsigned char value = stream.get(); if ((value!=0) && (value!=0xff)) rumstring += value; } else { stream.skip(1); } } } catch (...) {return empty;} if (rumstring.length()>offset) return rumstring.substr(offset); else return empty; } bool RPCRQProcessor::doAllParsingWork( DataStream& request, DataStream& response, EventParsingContext &context ) { try { rum::public_sdk::ActionInfo iactionInfo = context.getActionInfo(); String schema = " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">"; String strdata = stream_to_string(request,45); String message = search_substring(strdata,"<message type=\"RPC_","</message>"); if (message!="") { String msgType = search_substring(strdata,"<message type=\"","\">"); String origMsgID = search_substring(message,"<origMsgID>","</origMsgID>"); if (origMsgID=="") origMsgID = search_substring(message,"<origMsgID"+schema,"</origMsgID>"); String origSysID = search_substring(message,"<origSysID>","</origSysID>"); if (origSysID=="") origSysID = search_substring(message,"<origSysID"+schema,"</origSysID>"); String targSysID = search_substring(message,"<targSysID>","</targSysID>"); if (targSysID=="") targSysID = search_substring(message,"<targSysID"+schema,"</targSysID>"); String origPrcID = search_substring(message,"<origPrcID>","</origPrcID>"); if (origPrcID=="") origPrcID = search_substring(message,"<origPrcID"+schema,"</origPrcID>"); String timeStamp = search_substring(message,"<timeStamp>","</timeStamp>"); if (timeStamp=="") timeStamp = search_substring(message,"<timeStamp"+schema,"</timeStamp>"); String CmdName = search_substring(message,"<command name=\"","\">"); if (CmdName=="") CmdName = "PARSING_ERROR"; iactionInfo.addKeyValue("msgType" , msgType , false ); iactionInfo.addKeyValue("origMsgID", origMsgID, false ); iactionInfo.addKeyValue("origSysID", origSysID, false ); iactionInfo.addKeyValue("targSysID", targSysID, false ); iactionInfo.addKeyValue("origPrcID", origPrcID, false ); iactionInfo.addKeyValue("timeStamp", timeStamp, false ); iactionInfo.addKeyValue("CmdName" , CmdName, false ); iactionInfo.addKeyValue("x-action-descriptor" , CmdName, false ); iactionInfo.setDescriptor(CmdName); String respstrdata = stream_to_string(response,45); String resmessage = search_substring(respstrdata,"<message type=\"RPC_","</message>"); if (resmessage!="") { String retCode = search_substring(resmessage,"<retCode>","</retCode>"); if (retCode!="") { iactionInfo.addKeyValue("retCode" , retCode, false ); if (retCode.find("OK") != std::string::npos) { context.getEvent().setStatusCode(0); } else context.getEvent().setStatusCode(1); } else { iactionInfo.addKeyValue("retCode" , "NOTFOUND", false ); context.getEvent().setStatusCode(2); } } } if (message=="") return false; else return true; } catch (...) { LOG4PROBE_ERROR( getDefaultLogger(), "exception in RPCRQProcessor" ); context.getEvent().setStatusCode(3); } } ////////////////////////////////////////////////////////////// // class MyProtocolParser::EventParsingContext ////////////////////////////////////////////////////////////// RPCRQProcessor::EventParsingContext::EventParsingContext( ProtocolEvent& event ) : _event(event) { try { _connectionContext = _event.getSessionContext(); if ( NULL == _connectionContext.get() ) { _connectionContext = new ConnectionInfo(); _event.setSessionContext( _connectionContext.get() ); } } catch (...) { std::ofstream fileSTRINGTEST; fileSTRINGTEST.open("/home/rum/fileSTRINGTEST_error2.out",std::ios::out|std::ios::app|std::ios::binary); fileSTRINGTEST << "--------------------------------\n"; fileSTRINGTEST.close(); } } // Declaring Factory for creating processor RUM_PROBE_EXPORT_PROCESSOR( RPCRQProcessor, getRPCRQProcessor);
      
      







出力は非常にエレガントなレポートでした:







顧客は満足し、製品の新しいスキルを獲得しました。



ISO8583プロトコルに従ってデータを分析します



タスクは以前のタスクに似ていますが、少し変更されています。



「みんな、トラフィックの新しい部分です。 ATMとPOS端末からトランザクションを収集するアグリゲーターがあります。 すべてのトランザクションはABSに送られます。 このようなトランザクションの数、ステータス、各リクエストの実行時間を知りたいです。 出力はグラフレポートです。」



前のタスクと同様に、ネットワークトラフィックパケットはXMLでした。 フィールドの数が非常に多い場合のみ。 新しいコードの助けを借りて、不要なものをすべて排除し、RPCの場合と同じ分析およびトランザクションカウント用のXMLを取得しました。

出口で、顧客はトランザクション数のスケジュールを受け取りました。 以下のスクリーンショットは、毎週の間隔を示しています。 これで、このグラフの異常な動作はシステムによって障害として解釈されます。 イベントとビジネスプロセスの他のアプリケーションとの相関関係を調整しました。管理者は、標準からの逸脱の考えられる理由をすぐに確認できます。 もちろん、異なる日に、スケジュールの動作は異なる場合があります。 たとえば、土曜日と日曜日には、日中のトランザクション数による沈下はありません。これは週末の標準であり、イベントは生成されません。 これがそのような人工知能です。







ユーザートラフィック監視システムを使用して、2つの重要な利点を特定しました(さらに多くの利点があるかもしれませんが、これまで2つに焦点を合わせてきました)。



  1. ビジネスアプリケーションに追加の負荷はありません。 特別なエージェントをアプリケーションに統合する必要はありません。そこで管理者に何かを再起動する許可を求め、一般に何もせずに人々を混乱させます。
  2. 「ブラックボックス」を制御する機能。 そのようなアプリケーションは数多くあり、それらをどのようにフォローするかが必ずしも明確ではありません。 例は、ABSの状況です。


アンケートに答えて、ブラックボックスアプリケーションのコメント例を共有し、それらをどのように制御するかを教えてください。



この記事の著者は、Technoserv社の監視システムの設計者であるAnton Kasimovです。



All Articles