Ćwiczenie — monitorowanie błędów przejściowych w aplikacji przy użyciu rejestrowania
W tym ćwiczeniu ulepszymy bieżące rejestrowanie aplikacji do czatu, tworząc kod z poprzednich ćwiczeń.
Dla uproszczenia koncentrujemy się na rejestrowaniu komunikatów w konsoli w tym ćwiczeniu. Poniższa lista zawiera informacje, które chcesz rejestrować:
- Czas wystąpienia błędu
- Liczba ponownych prób
- Czas naprawienia błędu
- Lokalizacja w kodzie
- Błędy przejściowe powinny znajdować się na poziomie ostrzeżeń
- Wyjątki powodujące zamknięcie aplikacji powinny być błędami
Napiszesz kod w taki sposób, aby można było go rozbudować w przyszłości w celu zapisywania komunikatów dziennika do plików lub innych usług, takich jak Azure Application Insights.
Dodawanie dostawcy rejestrowania
Firma Microsoft oferuje pakiet NuGet Microsoft.Extensions.Logging
, który dodaje zestaw doskonałych funkcji rejestrowania. Można go dostosować z użyciem dostawców. Pakiet ma wbudowanego dostawcę konsoli, który pozwala na rejestrowanie komunikatów w konsoli. Możesz również użyć nowych funkcji wstrzykiwania zależności platformy .NET Core, aby umożliwić wyświetlanie komunikatów dzienników w celu wydrukowania klasy, w której się znajdują.
Upewnij się, że nadal jesteś w folderze chatapp-retry języka C# za pomocą następującego polecenia.
cd ~/mslearn-handle-transient-errors-in-your-app/csharp/chatapp-retry/
W usłudze Cloud Shell dodaj
Microsoft.Extensions.Logging
do aplikacji, instalując następujące trzy zależności.dotnet add package Microsoft.Extensions.Logging --version 2.2.0
dotnet add package Microsoft.Extensions.DependencyInjection --version 2.2.0
dotnet add package Microsoft.Extensions.Logging.Console --version 2.2.0
Przed kontynuowaniem tego ćwiczenia upewnij się, że pomyślnie zainstalowano wszystkie trzy pakiety.
Wprowadź poniższe polecenie w edytorze usługi Cloud Shell.
code .
Zostanie otwarty edytor kodu, a wszystkie pliki w bieżącym folderze będą wyświetlane w oknie nawigacji po lewej stronie.
Wybierz plik Program.cs w oknie nawigacji po lewej stronie, aby otworzyć go w edytorze.
Odwołaj się do elementu
Microsoft.Extensions.Logging
w pliku Program.cs, dodając instrukcjeusing
, jak pokazano w poniższym fragmencie kodu.using Microsoft.Extensions.Logging; using Microsoft.Extensions.DependencyInjection;
Dodaj prywatny element członkowski do klasy dla naszego obiektu rejestrowania.
private static ILogger main_logger;
Dodawanie rejestrowania
Dodaj następujący kod do początku metody
Main()
w pliku Program.cs.// Instantiate Dependency Injection and configure logger var serviceProvider = new ServiceCollection() .AddLogging(cfg => cfg.AddConsole()) .Configure<LoggerFilterOptions>(cfg => cfg.MinLevel=LogLevel.Debug) .BuildServiceProvider(); // Set instances of logger var logger = serviceProvider.GetService<ILogger<RetryPolicy>>(); main_logger = serviceProvider.GetService<ILogger<Program>>(); retries = new RetryPolicy(logger);
Powyższy kod tworzy wystąpienie klasy ServiceCollection, dodaje dostawcę konsoli i ustawia domyślny poziom rejestrowania w celu debugowania. W następnych dwóch wierszach zostaną utworzone dwa rejestratory: jeden do użycia w klasie zasad ponawiania, a drugi dla głównej aplikacji.
Utworzyliśmy zasady ponawiania w poprzednim kodzie, więc teraz należy zmienić następujący kod:
private static RetryPolicy retries = new RetryPolicy();
Do:
private static RetryPolicy retries;
Zastąp element
getAllChats
następującą aktualizacją. Ten kod zastępuje wszystkieConsole.WriteLine
wywołania związane z błędami systemowymi, ale utrzymuje wywołaniaConsole.WriteLine
interfejsu użytkownika.private static void getAllChats() { messages = database.GetCollection<ChatMessage>(collectionName); try { allMessages = messages.Find(new BsonDocument()).ToList(); foreach (ChatMessage chat in allMessages) { Console.WriteLine($"{chat.Name}: {chat.Message}"); main_logger.LogInformation($"{DateTime.Now} - Messages read from database."); } Console.WriteLine("\n"); } catch (MongoDB.Driver.MongoConnectionException e) { if (retries.CanRetry()) { diagnose(e); getAllChats(); //retry } else { main_logger.LogError($"{DateTime.Now} - Maximum retries - need to close."); throw e; } } catch (System.TimeoutException e) { if (retries.CanRetry()) { diagnose(e); getAllChats(); //retry } else { main_logger.LogError($"{DateTime.Now} - Maximum retries - need to close."); throw e; } } catch (Exception e) { main_logger.LogError($"{DateTime.Now} - Full stack trace: {e.StackTrace}"); throw e; } }
Rozszerzyliśmy rejestrowanie z głównej aplikacji, a teraz skupimy się utworzonej wcześniej klasie
RetryPolicy
. KlasaRetryPolicy
musi również przeprowadzić rejestrowanie, aby dodać istotne informacje na temat błędów przejściowych.Wybierz trzy wielokropki (...) u góry po prawej stronie edytora, a następnie wybierz pozycję Zapisz.
Wybierz plik RetryPolicy.cs w oknie nawigacji po lewej stronie, aby otworzyć plik RetryPolicy.cs w edytorze kodu.
Dodaj odwołanie do biblioteki rejestrowania za pomocą następującej instrukcji
using
.using Microsoft.Extensions.Logging;
Dodaj prywatny element członkowski do klasy dla naszego obiektu rejestrowania.
private readonly ILogger retrylogger;
Zaktualizuj konstruktor klasy przy użyciu następującego kodu, aby utworzyć wystąpienie rejestratora. Zwróć uwagę, że konstruktor przyjmuje teraz parametr typu
ILogger
.public RetryPolicy(ILogger logger) { retrylogger = logger; ConfigurationBuilder configurationBuilder = new ConfigurationBuilder(); configurationBuilder.SetBasePath(Directory.GetCurrentDirectory()); configurationBuilder.AddJsonFile("appsettings.json"); configuration = configurationBuilder.Build(); }
Zastąp wywołanie
Console.WriteLine
w elemencieCanRetry
:Console.WriteLine($"Retrying: {currentTries}");
Tym:
retrylogger.LogWarning($"{DateTime.Now} - Retries: {currentTries}");
Zapisz plik i zamknij edytor. Użyj poleceń w menu ... w prawym górnym rogu edytora lub użyj klawiszy skrótu Ctrl+S, aby zapisać plik, i Ctrl+Q, aby zamknąć edytor.
Skompiluj i uruchom aplikację.
dotnet build dotnet run
Dodawanie dostawcy rejestrowania
Środowisko uruchomieniowe języka Java oferuje bibliotekę import java.util.logging
, która dodaje zestaw doskonałych funkcji rejestrowania. Można ją dostosować z użyciem dostawców, komunikaty mogą mieć zastosowane formaty, a biblioteka będzie domyślnie rejestrować w konsoli. Nie musisz dodawać tej biblioteki do aplikacji do czatów, ponieważ jest już ona używana do ukrywania komunikatów dziennika bazy danych MongoDB. Dodasz nowy rejestrator do użycia w głównej aplikacji i zasady ponawiania prób, a następnie dodaj nową bibliotekę czasu, aby zezwolić na dostęp do bieżącej godziny.
W usłudze Cloud Shell przejdź do folderu chatapp-retry węzła.
cd ~/mslearn-handle-transient-errors-in-your-app/java/chatapp-retry/
Edytuj plik
javaChat.java
w edytorze kodu.code javaChat.java
Zaimportuj biblioteki procesów pomocniczych czasu przez dodanie poniższych instrukcji
import
do pliku javaChat.java.import java.time.format.DateTimeFormatter; import java.time.LocalDateTime;
Dodaj do niej zmienną
javaChat
prywatną składową rejestratora, która może być używana w całej aplikacji.private static Logger logger = Logger.getLogger( javaChat.class.getName() );
Zaktualizuj element
printAllMessages
do następującego kodu. Aktualizacja zastępuje wywołaniaSystem.out.Println
w blokach catch. Nadal istnieją wywołania elementuSystem.out.Println
dla interfejsu użytkownika.private static void printAllMessages (MongoCollection<Document> collection) throws InterruptedException { try { // Return all messages collection.find().forEach((Consumer<Document>) document -> { System.out.printf("%s: %s\n", document.get("name"), document.get("message")); }); } catch (com.mongodb.MongoCommandException e) { if (retries.canRetry()) { diagnose(e); printAllMessages(collection); //retry } else { System.out.println("Maximum retries - need to close."); throw e; } } catch (com.mongodb.MongoSecurityException e) { if (retries.canRetry()) { diagnose(e); printAllMessages(collection); //retry } else { System.out.println("Maximum retries - need to close."); throw e; } } catch (Exception e) { diagnose(e); throw e; } }
Klasa zasad ponawiania musi również przeprowadzić rejestrowanie, aby dodać istotne informacje na temat błędów przejściowych.
Wybierz trzy wielokropki (...) u góry po prawej stronie edytora, a następnie wybierz pozycję Zapisz.
Wybierz trzy wielokropki (...) u góry po prawej stronie edytora, a następnie wybierz pozycję Otwórz, w oknie dialogowym wpisz RetryPolicy.java i naciśnij klawisz Enter.
Zaimportuj biblioteki rejestrowania i czasu przez dodanie poniższych instrukcji
import
do klasy.import java.util.logging.Logger; import java.util.logging.Level; import java.time.format.DateTimeFormatter; import java.time.LocalDateTime;
Zadeklaruj zmienną dla wystąpienia naszego rejestratora.
private Logger retryLogger = Logger.getLogger( RetryPolicy.class.getName() );
Zastąp wywołanie
System.out.printf
w elemenciecanRetry()
komunikatem rejestrowania:System.out.printf("Retrying: %s\n", currentTries);
Tym:
retryLogger.log(Level.WARNING, LocalDateTime.now() + " - Retrying: " + currentTries);
Zapisz plik i zamknij edytor. Użyj poleceń w menu ... w prawym górnym rogu edytora lub użyj klawiszy skrótu Ctrl+S, aby zapisać plik, i Ctrl+Q, aby zamknąć edytor.
Skompiluj i uruchom aplikację.
javac -cp .:lib/* -d . javaChat.java RetryPolicy.java java -cp .:lib/* learn.javachatapp.javaChat
Dodawanie dostawcy rejestrowania
Ze względu na to, że środowisko Node.js opiera się na języku JavaScript, wbudowane biblioteki rejestrowania nie są udostępniane. Istnieje wiele innych bibliotek rejestrowania, ale Twój zespół zdecydował się na standaryzację w systemie Winston we wszystkich aplikacjach węzłów. Pakiet Winston może domyślnie zapisywać w konsoli i oferuje również opcje różnych operacji transportu i formatów komunikatów dziennika.
Upewnij się, że nadal znajdujesz się w folderze Node.js chatapp-retry , uruchamiając następujące polecenie.
cd ~/mslearn-handle-transient-errors-in-your-app/node/chatapp-retry/
Zainstaluj pakiet Winston.
npm install winston
Edytuj plik
server.js
w edytorze kodu.code server.js
Wymagaj nowej biblioteki rejestrowania Winston, dodając język JavaScript do wiersza 16.
const { createLogger, format, transports } = require('winston'); const logger = createLogger({ level: 'debug', format: format.combine( format.colorize(), format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), format.printf(info => `${info.timestamp} ${info.level}: ${info.message}`) ), transports: [new transports.Console()] });
Zastąp wszystkie wywołania
console.log
nowym rejestratorem.// Connect to MongoDB function connectWithRetry() { mongoose.connect( dbUrl, options ) .then(() => logger.log('info', 'Connection to MongoDB successful') ) .catch(function(e) { if (retries.checkRetries()) { connectWithRetry(); } else { logger.log('error', 'Error occured trying to connect to the database.'); } }); }
// Get all messages from the database app.get('/messages', (req, res) => { Message.find({}) .then(messages => { res.send(messages); logger.log('info', 'Messages Refreshed.'); }) .catch(function(e) { logger.log('error', 'Error reading from the database.' + e); }); } );
// Save a message app.post('/messages', (req, res) => { var message = new Message(req.body); message.save() .then( () => { res.sendStatus(200); logger.log('info', 'Message Posted.'); }) .catch(function(e) { logger.log('error', 'Error saving to the database.' + e); }); } );
// Delete all messages from the database app.post('/deleteall', (req, res) => { Message.deleteMany({}) .then( () => { res.sendStatus(200); logger.log('info', 'Messages Deleted.'); }) .catch(function(e) { logger.log('error', 'Error deleting from database.' + e); }); } );
Klasa zasad ponawiania musi również przeprowadzić rejestrowanie, aby dodać istotne informacje na temat błędów przejściowych.
Wybierz trzy wielokropki (...) u góry po prawej stronie edytora, a następnie wybierz pozycję Zapisz.
Wybierz trzy wielokropki (...) u góry po prawej stronie edytora, a następnie wybierz pozycję Otwórz, w oknie dialogowym wpisz retryPolicy.js i naciśnij klawisz Enter.
Rozszerz plik retryPolicy.js, aby rejestrować informacje o błędach przejściowych, dodając kod umożliwiający użycie pakietu Winston w wierszu 4.
const { createLogger, format, transports } = require('winston'); const logger = createLogger({ level: 'debug', format: format.combine( format.colorize(), format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), format.printf(info => `${info.timestamp} ${info.level}: ${info.message}`) ), transports: [new transports.Console()] });
Zastąp wiersz
console.log
w metodziecheckRetries
:console.log('Retrying: ' + this._currentTries);
Tym:
logger.log('warn', 'Retrying: ' + this._currentTries);
Zapisz plik i zamknij edytor. Użyj poleceń w menu ... w prawym górnym rogu edytora lub użyj klawiszy skrótu Ctrl+S, aby zapisać plik, i Ctrl+Q, aby zamknąć edytor.
Uruchom aplikację.
npm start
Napiwek
Jeśli w aplikacji nie masz już otwartej strony przeglądarki, uruchom polecenie curl -X POST http://localhost:8888/openPort/8000;
i kliknij adres URL.
Testowanie nowego rejestrowania
Jeśli zapora jest nadal włączona dla usługi Azure Cosmos DB, nie można połączyć aplikacji do czatów z bazą danych. W przeciwnym razie jeśli aplikacja do czatów jest nadal uruchomiona, wykonaj następujące kroki, aby włączyć zaporę.
Zaloguj się do witryny Azure Portal dla piaskownicy.
W menu witryny Azure Portal lub na stronie głównej wybierz pozycję Azure Cosmos DB.
Powinno zostać wyświetlone konto bazy danych z nazwą rozpoczynającą się od learn-cosmos-db-. Wybierz to konto bazy danych.
W panelu usługi Azure Cosmos DB wybierz pozycję Zapory i sieci wirtualne.
Wybierz pozycję Wybrane sieci.
Usuń zaznaczenie pola wyboru Zezwalaj na dostęp z witryny Azure Portal.
Zaznacz pole wyboru Rozumiem, że bieżące ustawienia spowodują zablokowanie wszystkich sieci wirtualnych i adresów IP, w tym witrynę Azure Portal.
Wybierz pozycję Zapisz.
Wróć do usługi Cloud Shell i spróbuj odświeżyć komunikaty. W konsoli powinny zostać wyświetlone nowe komunikaty rejestrowania, podobne do poniższych.
warn: csharp_chatapp_retry.RetryPolicy[0]
20/03/2019 10:37:24 - Retries: 1
warn: csharp_chatapp_retry.Program[0]
Exception raised: System.TimeoutException
warn: csharp_chatapp_retry.RetryPolicy[0]
20/03/2019 10:37:29 - Retries: 2
warn: csharp_chatapp_retry.Program[0]
Exception raised: System.TimeoutException
warn: csharp_chatapp_retry.RetryPolicy[0]
20/03/2019 10:38:34 - Retries: 3
warn: csharp_chatapp_retry.Program[0]
Exception raised: System.TimeoutException
warn: csharp_chatapp_retry.RetryPolicy[0]
20/03/2019 10:39:39 - Retries: 4
warn: csharp_chatapp_retry.Program[0]
Exception raised: System.TimeoutException
warn: csharp_chatapp_retry.RetryPolicy[0]
20/03/2019 10:40:44 - Retries: 5
fail: csharp_chatapp_retry.Program[0]
20/03/2019 10:41:44 - Maximum retries - need to close.
Mar 20, 2019 11:35:30 AM learn.javachatapp.RetryPolicy checkRetries
WARNING: 2019-03-20T11:35:30.484755400 - Retrying: 1
Mar 20, 2019 11:35:30 AM learn.javachatapp.javaChat diagnose
WARNING: 2019-03-20T11:35:30.523755300 - Exception raised: com.mongodb.MongoSecurityException: Exception authenticating
Mar 20, 2019 11:35:30 AM learn.javachatapp.RetryPolicy checkRetries
WARNING: 2019-03-20T11:35:30.680967900 - Retrying: 2
Mar 20, 2019 11:36:30 AM learn.javachatapp.javaChat diagnose
WARNING: 2019-03-20T11:36:30.682929400 - Exception raised: com.mongodb.MongoSecurityException: Exception authenticating
Mar 20, 2019 11:36:30 AM learn.javachatapp.RetryPolicy checkRetries
WARNING: 2019-03-20T11:36:30.898297400 - Retrying: 3
Mar 20, 2019 11:37:30 AM learn.javachatapp.javaChat diagnose
WARNING: 2019-03-20T11:37:30.901201300 - Exception raised: com.mongodb.MongoSecurityException: Exception authenticating
Mar 20, 2019 11:37:31 AM learn.javachatapp.RetryPolicy checkRetries
WARNING: 2019-03-20T11:37:31.125043 - Retrying: 4
Mar 20, 2019 11:38:31 AM learn.javachatapp.javaChat diagnose
WARNING: 2019-03-20T11:38:31.126188100 - Exception raised: com.mongodb.MongoSecurityException: Exception authenticating
Mar 20, 2019 11:38:31 AM learn.javachatapp.RetryPolicy checkRetries
WARNING: 2019-03-20T11:38:31.329202 - Retrying: 5
Mar 20, 2019 11:39:31 AM learn.javachatapp.javaChat printAllMessages
SEVERE: 2019-03-20T11:39:31.330523900 - Maximum retries - need to close.
Exception in thread "main" com.mongodb.MongoSecurityException: Exception authenticating
2019-03-20 14:06:45 warn: Retrying: 1
2019-03-20 14:06:45 warn: Retrying: 2
2019-03-20 14:07:45 warn: Retrying: 3
2019-03-20 14:08:45 warn: Retrying: 4
2019-03-20 14:09:45 warn: Retrying: 5
2019-03-20 14:10:45 error: Error occurred trying to connect to the database.