1. 上位システムによって不正なパラメータが導入されました。不正なパラメータによって引き起こされたエラーの場合、パラメータ検証と前提条件検証を通じてエラーを阻止できます;
2. 基礎となるシステムとの対話によって生成されたエラー。下位層とのやり取りによって発生するエラーには 2 種類あります:
a. 下位層システムは正常に処理されますが、通信エラーが発生し、サブシステム間でデータの不整合が発生します。
# この状況では、タイムアウト補償メカニズムを使用して事前にタスクを記録し、後でスケジュールされたタスクを通じてデータを修正できます。 より良い設計ソリューションがある場合は、メッセージを残すこともできます。 b. 通信は成功しましたが、下位層の処理でエラーが発生しました。 この場合、サブシステム間の相互作用を調整するために下位レベルの開発者と通信する必要があります; エラーコードに応じて適切に処理するか、適切な処置を行う必要があります下位層によって返されたエラーの説明、プロンプト情報。 いずれの場合でも、基盤となるシステムの信頼性は平均的であると想定し、エラーに対する設計上の考慮を行う必要があります。3. この層のシステム処理にエラーがあります。
システムのこの層でのエラーの原因:原因 1: 過失が原因です。省略とは、プログラマがそのようなエラーを回避できたにもかかわらず、回避できなかったことを意味します。たとえば、&& が & に入力され、== が = に入力されました; 境界エラー、複合ロジックの判断エラーなど。怠慢とは、プログラマが疲れていたり、徹夜で残業していたり、会議をしながらプログラムを書いていたりするなどの集中力の欠如によるもの、またはプログラマがプログラムの堅牢性などを考慮せずに機能の実装を急いでしまったことによるものです。
改善策: このような問題を効果的に回避するには、コード静的解析ツールと単体テスト行のカバレッジを使用します。原因 2: エラーおよび例外処理が不十分であることが原因です。たとえば、質問を入力します。 2 つの数値の加算を計算する場合、計算オーバーフローの問題だけでなく、不正な入力の状況も考慮する必要があります。前者については、理解、間違い、経験によって回避できる可能性がありますが、後者については、正規表現を使用して不正な入力をフィルタリングするなど、IQ が制御できる範囲内に制限する必要があります。正規表現はテストする必要があります。違法な入力については、できるだけ詳細でわかりやすくフレンドリーな情報、理由、提案を提供してください。
改善策: さまざまなエラー状況や例外処理をできるだけ総合的に検討してください。メイン プロセスを実装した後、考えられるさまざまなエラーと例外を慎重に検討し、適切なエラー コードとエラーの説明を返すステップを追加します。各インターフェイスまたはモジュールは独自のエラーと例外を効果的に処理するため、複雑なシーンの相互作用によって引き起こされるバグを効果的に回避できます。
たとえば、ビジネス ユース ケースは、シナリオ A.B.C の対話によって完了します。 A.B の実際の実行は成功しますが、C は失敗します。このとき、B は C から返された適切なコードとメッセージをロールバックし、適切なコードとメッセージを A に返す必要があります。A は B の戻りに基づいてロールバックし、適切なコードとメッセージを返します。コードとメッセージをクライアントに送信します。これはセグメント化されたロールバック メカニズムであり、各シナリオで異常な状況下でのロールバックを考慮する必要があります。理由 3: 論理結合が密であることが原因です。ビジネスロジックの密結合により、ソフトウェア製品が段階的に発展するにつれて、さまざまな論理関係が複雑かつ複雑になり、全体の状況が見えにくくなり、局所的な変更の影響がグローバルな範囲に波及し、予測不能な問題が発生することがあります。 。
改善策: 短い関数と短いメソッドを記述します。各関数またはメソッドは 50 行を超えないようにしてください。ステートレスな関数とメソッド、読み取り専用のグローバル状態を記述し、同じ前提条件は常に同じ結果を出力し、外部状態に応じて動作を変更しません。インターフェイス間の接続を確立するための合理的な構造、インターフェイス、および論理セグメントを定義します。可能な限り直交かつ低結合であること、サービス層については、可能な限りシンプルで直交したインターフェースを提供すること、アプリケーションのモジュール化と疎結合を維持し、論理的な依存関係を明確にするために継続的な再構築を実行する必要があります。 多数のビジネス インターフェイスが相互に対話する状況では、各ビジネス インターフェイスの論理プロセスと相互依存関係を整理し、全体として最適化する必要があります。多数の状態を持つエンティティの場合、関連するビジネス インターフェイスも整理する必要があり、状態間の遷移関係を整理します。原因 4: 不正なアルゴリズムが原因です。
改善策: まずアルゴリズムをアプリケーションから分離します。アルゴリズムに複数の実装がある場合は、並べ替え操作などのクロスチェックの単体テストを通じて確認できます。アルゴリズムに可逆的な特性がある場合は、暗号化および復号化操作などの可逆チェックの単体テストを通じて確認できます。 。原因 5: 同じ型のパラメータが間違った順序で渡されます。たとえば、modifyFlow(int rx, int tx) の場合、実際の呼び出しはmodifyFlow(tx,rx)です。
改善策: 型をできるだけ具体的にします。浮動小数点数を使用する必要がある場合は浮動小数点数を使用し、文字列を使用する必要がある場合は文字列を使用し、特定のオブジェクト タイプを使用する必要がある場合は特定のオブジェクト タイプを使用します。同じタイプのパラメータはできる限りずらして配置する必要があります。上記のいずれも使用できない場合は、同じタイプのパラメータをできるだけずらして配置する必要があります。満足している場合は、インターフェイス テストを通じて検証する必要があります。インターフェイス パラメーターの値は異なっている必要があります。原因 6: Null ポインタ例外。 Null ポインター例外は通常、オブジェクトが正しく初期化されていない場合、またはオブジェクトが使用前に null でないかどうかがチェックされていない場合に発生します。
改善策: 設定オブジェクトの場合は初期化が成功しているか、通常のオブジェクトの場合は使用するエンティティオブジェクトを取得する前にnullでないことを確認してください。
原因 7: ネットワーク通信エラー。ネットワーク通信エラーは通常、ネットワークの遅延、輻輳、または遮断によって発生します。ネットワーク通信エラーは通常、低確率のイベントですが、低確率のイベントは大規模な障害や再現が困難なバグにつながる可能性があります。
改善策: 前のサブシステムのエンドポイントと次のサブシステムのエントリポイントにそれぞれINFOログを作成します。両者の時間差が手がかりとなります。
原因 8: トランザクションおよび同時実行エラー。トランザクションと同時実行性を組み合わせると、特定が非常に困難なエラーが簡単に発生する可能性があります。
改善策: 共有変数や重要なステータス変更を伴うプログラム内での同時操作については、INFO ログを追加する必要があります。
より効果的な方法がある場合は、メッセージを残して指摘してください。
原因 9: 構成エラー。
改善策: アプリケーションの起動時または対応する設定の開始時に、すべての設定項目を検出し、対応する INFO ログを出力し、すべての設定が正常に読み込まれていることを確認します。
原因 10: ビジネスに不慣れなことが原因で発生したエラー。中規模および大規模システムでは、一部のビジネス ロジックとビジネス インタラクションは比較的複雑であり、ビジネス ロジック全体は複数の開発学生の脳内に存在する可能性があり、全員の理解は不完全です。これにより、ビジネスコーディングエラーが発生しやすくなります。
改善策: 複数人でのディスカッションとコミュニケーションを通じて正しいビジネス ユース ケースを設計し、ビジネス ユース ケースに基づいてビジネス ロジックを記述して実装します。最終的なビジネス ロジックとビジネス ユース ケースは、完全にアーカイブされている; ビジネス インターフェイスはビジネスの前提条件、処理ロジック、事後検証および注意事項を示している; ビジネスが変更された場合、ビジネス コメントは同時に更新する必要がある; コード REVIEWビジネス アノテーションはビジネス インターフェイスの重要なドキュメントであり、ビジネスの理解において重要なキャッシュの役割を果たします。
原因 11: 設計上の問題によって発生するエラー。たとえば、同期シリアル方式にはパフォーマンスと遅い応答の問題があり、一方、同時非同期方式はパフォーマンスと遅い応答の問題を解決できますが、セキュリティと正確性に隠れた危険をもたらします。非同期アプローチはプログラミング モデルの変更につながり、非同期メッセージのプッシュと受信などの新しい問題が追加されます。キャッシュを使用するとパフォーマンスが向上しますが、キャッシュの更新で問題が発生します。
改善策: 設計書を作成し、慎重にレビューします。設計文書には、背景、要件、達成すべきビジネス目標、達成すべきビジネスパフォーマンス指標、起こり得る影響、全体的な設計アイデア、詳細な計画、計画の長所、短所、考えられる影響をテストと受け入れを通じて予測する必要があります。変更が確実にビジネス目標とビジネス パフォーマンス指標を満たしていることを確認します。
原因 12: 詳細が不明なためエラーが発生しました。バッファ オーバーフローや SQL インジェクション攻撃など。機能的には問題ありませんが、悪用の観点からは抜け穴があります。別の例として、JSON 文字列解析に jackson ライブラリを選択した場合、デフォルトでは、新しいフィールドがオブジェクトに追加されるときに解析エラーが発生します。変更に正しく応答するには、 @JsonIgnoreProperties(ignoreUnknown = true) アノテーションをオブジェクトに追加する必要があります。他の JSON ライブラリを選択した場合は、この問題が発生しない可能性があります。
改善策: 経験を蓄積する一方で、セキュリティの問題や例外を考慮し、成熟した厳密にテストされたライブラリを選択する必要があります。
理由 13: 時間の経過とともに現れるバグ。過去には素晴らしいと思われたソリューションが、現在または将来のシナリオでは扱いにくくなったり、役に立たなくなったりすることは珍しくありません。たとえば、暗号化および復号化のアルゴリズムは、以前は完璧であると考えられていましたが、解読された後は注意して使用する必要があります。
改善策: 変更や脆弱性修復のニュースに注意し、古いコード、ライブラリ、動作を速やかに修正してください。
原因 14: ハードウェア関連のエラー。たとえば、メモリ リーク、ストレージ領域の不足、OutOfMemoryError などです。
改善策: アプリケーション システムの CPU/メモリ/ネットワークなどの重要な指標のパフォーマンス監視を強化します。
システムで発生する一般的なエラー:
データベース内のエンティティ レコードが存在しません。エンティティまたはエンティティ識別子を指定する必要があります。
エンティティ構成が正しくない場合は、問題のある構成と正しい構成を指定する必要があります;
エンティティ リソースが満たさない場合条件では、現在のリソースとそのリソースを指定する必要があります。要件は何ですか;
エンティティ操作の前提条件が満たされていない場合は、どのような前提条件を指定する必要がありますか満たす必要がある内容と現在のステータス;
エンティティ操作の事後チェックが満たされない場合は、満たす必要がある事後チェックとその内容を指定する必要があります。現在のステータスは次のとおりです;
パフォーマンスの問題によりタイムアウトが発生しました。パフォーマンスの原因を指定する必要があります。 質問、今後の最適化方法;
インタラクション複数のサブシステム間の通信エラーにより、ステータスやデータの不整合が発生しますか?
一般に、見つけるのが難しいエラーは、比較的低レベルの場所に表示されます。最下層では特定のビジネス シナリオを予測できないため、表示されるエラー メッセージは比較的一般的なものです。
これには、ビジネスの上層部にできるだけ多くの手がかりを提供する必要があります。このエラーは、複数のシステムまたはレイヤーの相互作用中に、スタックの特定のレイヤーで前提条件が満たされていないことが原因で発生するはずです。プログラミングするときは、スタックの各層で必要な前提条件がすべて満たされていることを確認し、間違ったパラメータを最下層に渡すことをできる限り避け、ビジネス層でエラーをできる限り遮断するようにしてください。
ほとんどのエラーは、さまざまな理由が組み合わさって発生します。しかし、どんな間違いにも必ず原因があるはずです。エラーを解決した後、エラーがどのように発生したのか、またエラーの再発を回避する方法を詳細に分析します。熱心に取り組むことで成功することはできますが、反省することによってのみ進歩することができます。推奨事項: Java のエレガントなロギング: log4j 実践編
問題のトラブルシューティングを容易にするエラー ログの書き方
エラー ロギングの基本原則:
できるだけ完全な内容を実現します。各エラー ログには、どのようなシナリオでどのようなエラーが発生したか、その理由 (または考えられる理由)、解決方法 (または解決策のヒント) が完全に説明されています。
おそらく具体的です。 。たとえば、NC リソースが不十分な場合、それは正確に何を指すのか、プログラムを通じて直接指定できるかどうか、VM NOT EXIST などの一般的なエラーの場合は、それが発生するシナリオを指定する必要があります。その後の統計作業を容易にします。
できるだけ直接的に。理想的なエラー ログでは、本当の原因を見つけるためにいくつかの手順を踏まなくても、最初の直感で原因とその解決方法を知ることができる必要があります。
既存のエクスペリエンスをシステムに直接統合します。解決されたすべての問題と経験は、他の場所に埋もれるのではなく、新入社員により良いヒントを提供できるように、できるだけフレンドリーな方法でシステムに統合される必要があります。
レイアウトは整然としており、フォーマットは統一され標準化されている必要があります。密度の高いエッセイのようなログは、見ているだけで心が痛むばかりで、非常に不親切で、問題のトラブルシューティングには不便です。
複数のキーワードを使用してリクエスト を一意に識別し、時間、エンティティ識別子 (vmname など)、操作名などのキーワードを強調表示します。
ログインからログ ファイルを開くまで。アプリケーションサーバーが複数あるため、いちいちログインして閲覧するのは不便です。すべてのサーバー ログを AG で直接表示したり、必要なエラー ログを直接フィルタリングしたりするためには、ツールを作成して AG に配置する必要があります。
エラー ログの場所を見つけます。現在のログのレイアウトは密集しているため、エラー ログを見つけるのが困難です。一般に、最初に「time」を使用してエラー ログの先頭付近の位置を特定し、次にエンティティ キーワードと操作名の組み合わせを使用してエラー ログの位置をロックします。 requestId に基づいてエラー ログを見つける方法はより伝統的ですが、最初に requestId を見つける必要があり、説明的ではありません。時間/内容のキーワードに基づいてエラー ログの場所を直接見つけることが最善です。
エラーログを分析します。エラー ログの内容は、より直接的かつ明確である必要があり、調査対象の現在の問題の特性と一致していることを明確に示し、重要な手がかりを提供する必要があります。
通常、プログラム エラー ログの問題は、ログの内容が現在のコードの状況に基づいてしか理解できないことです。ログは簡潔に見えますが、常に不完全に記述されており、半英語形式になっています。コードの状況をそのままにしておくと、何が起こっているのかを知るのは困難です。それは何ですか? ログの意味を理解するには、それについて考えるか、コードを見る必要があります。これは自ら招いた苦しみではないでしょうか?拡張: 主流の Java ロギング ツール ライブラリについて詳しく説明します。例:if ((storageType == StorageType.dfs1 || storageType == StorageType.dfs2) && (zone.hasStorageType(StorageType.io3) || zone.hasStorageType(StorageType.io4))) { // 进入dfs1 和dfs2 在io3 io4 存储。 } else { log.info("zone storage type not support, zone: " + zone.getZoneId() + ", storageType: " + storageType.name()); throw new BizException(DeviceErrorCode.ZONE_STORAGE_TYPE_NOT_SUPPORT); }
エラー ログは、コードのコンテキストを離れた場合でも、何が起こったのかを明確に説明できる必要があります。
また、エラーログに直接理由を記載できれば、検査ログ作成の手間が省けます。 ある意味、エラー ログは、実行中のさまざまな違法なユースケースを記録する非常に有用なドキュメントでもあります。 現在のプログラム エラー ログの内容には、次の問題がある可能性があります:1. エラー ログには、エラー パラメーターと内容が指定されていません:
catch(Exception ex){ log.error("control ip insert failed", ex); return new ResultSet<AddControlIpResponse>( ControlIpErrorCode.ERROR_CONTROL_IP_INSERT_FAILURE); }
log.error("Get some errors when insert subnet and its IPs into database. Add subnet or IP failure.", e);
解决方案:使用 String.format("Some msg to ErrorObj: %s", errobj) 方法指明错误参数及内容。
这通常要求对 DO 对象编写可读的 toString 方法。
2.错误场景不明确:
log.error("nc has exist, nc ip" + request.getIp());
在 createNc 中检测到 NC 已经存在报错。但是日志上没有指明错误场景, 让人猜测,为什么会报NC已存在错误。
可以改为
log.error("nc has exist when want to create nc, please check nc parameters. Given nc ip: " + request.getIp()); log.error("[create nc] nc has exist, please check nc parameters. Given nc ip: " + request.getIp());
类似的还有:
log.error("not all vm destroyed, nc id " + request.getNcId());
改成
log.error("[delete nc] some vms [%s] in the nc are not destroyed. nc id: %s", vmNames, request.getNcId());
解决方案:错误消息加上 when 字句, 或者错误消息前加上 【接口名】, 指明错误场景,直接从错误日志就知道明白了。
一般能够知道 executor 的可以加上 【接口名】, service 加上 when 字句。
3.内容不明确, 或不明其义:
if(aliMonitorReporter == null) { log.error("aliMonitorReporter is null!"); } else { aliMonitorReporter.attach(new ThreadPoolMonitor(namePrefix, asynTaskThreadPool.getThreadPoolExecutor())); }
改为:
log.error("aliMonitorReporter is null, probably not initialized properly, please check configuration in file xxx.");
类似的还有:
if (diskWbps == null && diskRbps == null && diskWiops == null && diskRiops == null) { log.error("none of attribute is specified for modifying"); throw new BizException(DeviceErrorCode.NO_ATTRIBUTE_FOR_MODIFY); }
改为
log.error("[modify disk attribute] None of [diskWbps,diskRbps,diskWiops,diskRiops] is specified for disk id:" + diskId);
解决方案:更清晰贴切地描述错误内容。
4.排查问题的引导内容不明确:
log.error("get gw group ip segment failed. zkPath: " + LockResource.getGwGroupIpSegmnetLockPath(request.getGwGroupId()));
zkPath ? 如何去排查这个问题?我该去找谁?到哪里去查找更具体的线索?
解决方案:加上相应的背景知识和引导排查措施。
5.错误内容不够具体细致:
if (!ncResourceService.isNcResourceEnough(ncResourceDO, vmResourceCondition)) { log.error("disk space is not enough at vm's nc, nc id:" + vmDO.getNcId()); throw new BizException(ResourceErrorCode.ERROR_RESOURCE_NOT_ENOUGH); }
究竟是什么资源不够?目前剩余多少?现在需要多少?值得注意的是, 要指明这些要额外做一些事情, 可能会稍微影响性能。这时候需要权衡性能和可调试性。
解决方案:通过改进程序或程序技巧, 尽可能揭示出具体的差异所在, 减少人工比对的操作。
6.半英文句式读起来不够清晰明白,需要思考来拼凑起完整的意思:
log.warn("cache status conflict, device id "+deviceDO.getId()+" db status "+deviceDO.getStatus() +", nc status "+ status);
改为:
log.warn(String.format("[query cache status] device cache status conflicts between regiondb and nc, status of device '%s' in regiondb is %s , but is %s in nc.", deviceDO.getId(), deviceDO.getStatus(), status));
解决方案:改为自然可读的英文句式。
总结起来, 错误日志格式可以为:
log.error("[接口名或操作名] [Some Error Msg] happens. [params] [Probably Because]. [Probably need to do]."); log.error(String.format("[接口名或操作名] [Some Error Msg] happens. [%s]. [Probably Because]. [Probably need to do].", params));
或
log.error("[Some Error Msg] happens to 错误参数或内容 when [in some condition]. [Probably Because]. [Probably need to do]."); log.error(String.format("[Some Error Msg] happens to %s when [in some condition]. [Probably Because]. [Probably need to do].", parameters));
[Probably Reason]. [Probably need to do]. 在某些情况下可以省略;在一些重要接口和场景下最好能说明一下。
每一条错误日志都是独立的,尽可能完整、具体、直接说明何种场景下发生了什么错误,由什么原因导致,要采用什么措施或步骤。
问题:
1.String.format 的性能会影响打日志吗?
一般来说, 错误日志应该是比较少的, 使用 String.format 的频度并不会太高,不会对应用和日志造成影响。
2.开发时间非常紧张时, 有时间去斟酌字句吗?
建立一个标准化的内容格式,将内容往格式套,可以节省斟酌字句的时间。
3.什么时候使用 info, warn , error ?
info 用于打印程序应该出现的正常状态信息, 便于追踪定位;
warn 表明系统出现轻微的不合理但不影响运行和使用;
error 表明出现了系统错误和异常,无法正常完成目标操作。
错误日志是排查问题的重要手段之一。当我们编程实现一项功能时, 通常会考虑可能发生的各种错误及相应原因:
要排查出相应的原因, 就需要一些关键描述来定位原因。
这就会形成三元组:
错误现象 -> 错误关键描述 -> 最终的错误原因。
需要针对每一种错误尽可能提供相应的错误关键描述,从而定位到相应的错误原因。
以上がJava プロジェクトでエラー ログを出力する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。