Skip to content

Commit

Permalink
Added logging to the external APIs
Browse files Browse the repository at this point in the history
  • Loading branch information
davewalker5 committed Sep 28, 2023
1 parent d859f71 commit bab92b3
Show file tree
Hide file tree
Showing 12 changed files with 158 additions and 28 deletions.
12 changes: 9 additions & 3 deletions src/BaseStationReader.Logic/Api/AirLabs/AirLabsAircraftApi.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using BaseStationReader.Entities.Interfaces;
using BaseStationReader.Entities.Logging;
using BaseStationReader.Entities.Tracking;

namespace BaseStationReader.Logic.Api.AirLabs
Expand All @@ -7,7 +8,7 @@ public class AirLabsAircraftApi : ExternalApiBase, IAircraftApi
{
private readonly string _baseAddress;

public AirLabsAircraftApi(ITrackerHttpClient client, string url, string key) : base(client)
public AirLabsAircraftApi(ITrackerLogger logger, ITrackerHttpClient client, string url, string key) : base(logger, client)
{
_baseAddress = $"{url}?api_key={key}";
}
Expand All @@ -19,7 +20,9 @@ public AirLabsAircraftApi(ITrackerHttpClient client, string url, string key) : b
/// <returns></returns>
public async Task<Dictionary<ApiProperty, string>?> LookupAircraft(string address)
{
return await MakeApiRequest($"&hex={address}");
Logger.LogMessage(Severity.Info, $"Looking up aircraft with address {address}");
var properties = await MakeApiRequest($"&hex={address}");
return properties;
}

/// <summary>
Expand Down Expand Up @@ -52,8 +55,11 @@ public AirLabsAircraftApi(ITrackerHttpClient client, string url, string key) : b
{ ApiProperty.ModelICAO, apiResponse!["icao"]?.GetValue<string>() ?? "" }
};
}
catch
catch (Exception ex)
{
var message = $"Error processing response: {ex.Message}";
Logger.LogMessage(Severity.Error, message);
Logger.LogException(ex);
properties = null;
}
}
Expand Down
17 changes: 12 additions & 5 deletions src/BaseStationReader.Logic/Api/AirLabs/AirLabsAirlinesApi.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
using BaseStationReader.Entities.Interfaces;
using BaseStationReader.Entities.Logging;
using BaseStationReader.Entities.Tracking;
using System.Text.Json.Nodes;

namespace BaseStationReader.Logic.Api.AirLabs
{
public class AirLabsAirlinesApi : ExternalApiBase, IAirlinesApi
{
private readonly string _baseAddress;

public AirLabsAirlinesApi(ITrackerHttpClient client, string url, string key) : base(client)
public AirLabsAirlinesApi(ITrackerLogger logger, ITrackerHttpClient client, string url, string key) : base(logger, client)
{
_baseAddress = $"{url}?api_key={key}";
}
Expand All @@ -19,6 +21,7 @@ public AirLabsAirlinesApi(ITrackerHttpClient client, string url, string key) : b
/// <returns></returns>
public async Task<Dictionary<ApiProperty, string>?> LookupAirlineByIATACode(string iata)
{
Logger.LogMessage(Severity.Info, $"Looking up airline with IATA code {iata}");
return await MakeApiRequest($"&iata_code={iata}");
}

Expand All @@ -29,6 +32,7 @@ public AirLabsAirlinesApi(ITrackerHttpClient client, string url, string key) : b
/// <returns></returns>
public async Task<Dictionary<ApiProperty, string>?> LookupAirlineByICAOCode(string icao)
{
Logger.LogMessage(Severity.Info, $"Looking up airline with ICAO code {icao}");
return await MakeApiRequest($"&icao_code={icao}");
}

Expand All @@ -55,13 +59,16 @@ public AirLabsAirlinesApi(ITrackerHttpClient client, string url, string key) : b
// Extract the values into a dictionary
properties = new()
{
{ ApiProperty.AirlineIATA, apiResponse!["iata_code"]!.GetValue<string>() },
{ ApiProperty.AirlineICAO, apiResponse!["icao_code"]!.GetValue<string>() },
{ ApiProperty.AirlineName, apiResponse!["name"]!.GetValue<string>() },
{ ApiProperty.AirlineIATA, apiResponse!["iata_code"]?.GetValue<string>() ?? "" },
{ ApiProperty.AirlineICAO, apiResponse!["icao_code"]?.GetValue<string>() ?? "" },
{ ApiProperty.AirlineName, apiResponse!["name"]?.GetValue<string>() ?? "" },
};
}
catch
catch (Exception ex)
{
var message = $"Error processing response: {ex.Message}";
Logger.LogMessage(Severity.Error, message);
Logger.LogException(ex);
properties = null;
}
}
Expand Down
40 changes: 38 additions & 2 deletions src/BaseStationReader.Logic/Api/ExternalApiBase.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using BaseStationReader.Entities.Interfaces;
using BaseStationReader.Entities.Logging;
using BaseStationReader.Entities.Tracking;
using System.Text.Json.Nodes;

namespace BaseStationReader.Logic.Api
Expand All @@ -7,8 +9,11 @@ public abstract class ExternalApiBase
{
private readonly ITrackerHttpClient _client;

protected ExternalApiBase(ITrackerHttpClient client)
protected ITrackerLogger Logger { get; private set; }

protected ExternalApiBase(ITrackerLogger logger, ITrackerHttpClient client)
{
Logger = logger;
_client = client;
}

Expand All @@ -35,12 +40,43 @@ protected ExternalApiBase(ITrackerHttpClient client)
}
}
}
catch
catch (Exception ex)
{
var message = $"Error calling {endpoint}: {ex.Message}";
Logger.LogMessage(Severity.Error, message);
Logger.LogException(ex);
node = null;
}

return node;
}

/// <summary>
/// Log the content of a properties dictionary resulting from an external API call
/// </summary>
/// <param name="properties"></param>
protected void LogProperties(Dictionary<ApiProperty, string?>? properties)
{
// Check the properties dictionary isn't NULL
if (properties != null)
{
// Not a NULL dictionary, so iterate over all the properties it contains
foreach (var property in properties)
{
// Construct a message containing the property name and the value, replacing
// null values with "NULL"
var value = property.Value != null ? property.Value.ToString() : "NULL";
var message = $"API property {property.Key.ToString()} = {value}";

// Log the message for this property
Logger.LogMessage(Severity.Info, message);
}
}
else
{
// Log the fact that the properties dictionary is NULL
Logger.LogMessage(Severity.Warning, "API lookup generated a NULL properties dictionary");
}
}
}
}
3 changes: 2 additions & 1 deletion src/BaseStationReader.Tests/AirLabsAircraftApiTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ public class AirLabsAircraftApiTest
[TestInitialize]
public void Initialise()
{
var logger = new MockFileLogger();
_client = new MockTrackerHttpClient();
_api = new AirLabsAircraftApi(_client, "", "");
_api = new AirLabsAircraftApi(logger, _client, "", "");
}

[TestMethod]
Expand Down
31 changes: 30 additions & 1 deletion src/BaseStationReader.Tests/AirLabsAirlinesApiTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,18 @@ namespace BaseStationReader.Tests
public class AirLabsAirlinesApiTest
{
private const string Response = "{\"response\": [{\"name\": \"Jet2.com\", \"iata_code\": \"LS\", \"icao_code\": \"EXS\"}]}";
private const string NoIATACode = "{\"response\": [{\"name\": \"Jet2.com\", \"iata_code\": null, \"icao_code\": \"EXS\"}]}";
private const string NoICAOCode = "{\"response\": [{\"name\": \"Jet2.com\", \"iata_code\": \"LS\", \"icao_code\": null}]}";

private MockTrackerHttpClient? _client = null;
private IAirlinesApi? _api = null;

[TestInitialize]
public void Initialise()
{
var logger = new MockFileLogger();
_client = new MockTrackerHttpClient();
_api = new AirLabsAirlinesApi(_client, "", "");
_api = new AirLabsAirlinesApi(logger, _client, "", "");
}

[TestMethod]
Expand Down Expand Up @@ -51,6 +54,32 @@ public void GetAirlineByICAOCodeTest()
Assert.AreEqual("Jet2.com", properties[ApiProperty.AirlineName]);
}

[TestMethod]
public void NoIATACodeTest()
{
_client!.AddResponse(NoIATACode);
var properties = Task.Run(() => _api!.LookupAirlineByICAOCode("EXS")).Result;

Assert.IsNotNull(properties);
Assert.AreEqual(3, properties.Count);
Assert.AreEqual("", properties[ApiProperty.AirlineIATA]);
Assert.AreEqual("EXS", properties[ApiProperty.AirlineICAO]);
Assert.AreEqual("Jet2.com", properties[ApiProperty.AirlineName]);
}

[TestMethod]
public void NoICAOCodeTest()
{
_client!.AddResponse(NoICAOCode);
var properties = Task.Run(() => _api!.LookupAirlineByICAOCode("EXS")).Result;

Assert.IsNotNull(properties);
Assert.AreEqual(3, properties.Count);
Assert.AreEqual("LS", properties[ApiProperty.AirlineIATA]);
Assert.AreEqual("", properties[ApiProperty.AirlineICAO]);
Assert.AreEqual("Jet2.com", properties[ApiProperty.AirlineName]);
}

[TestMethod]
public void InvalidJsonResponseTest()
{
Expand Down
5 changes: 3 additions & 2 deletions src/BaseStationReader.Tests/AircraftLookupManagerTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,10 @@ public void Initialise()
_manufacturerId = Task.Run(() => manufacturerManager.AddAsync(ManufacturerName)).Result.Id;

// Create the API wrappers
var logger = new MockFileLogger();
_client = new MockTrackerHttpClient();
var airlinesApi = new AirLabsAirlinesApi(_client, "", "");
var aircraftApi = new AirLabsAircraftApi(_client, "", "");
var airlinesApi = new AirLabsAirlinesApi(logger, _client, "", "");
var aircraftApi = new AirLabsAircraftApi(logger, _client, "", "");

// Finally, create a lookup manager
_manager = new AircraftLookupManager(_airlines, _details, _models, airlinesApi, aircraftApi);
Expand Down
7 changes: 4 additions & 3 deletions src/BaseStationReader.UI/Models/AircraftLookupModel.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using BaseStationReader.Data;
using BaseStationReader.Entities.Config;
using BaseStationReader.Entities.Interfaces;
using BaseStationReader.Entities.Lookup;
using BaseStationReader.Logic.Api;
using BaseStationReader.Logic.Api.AirLabs;
Expand All @@ -14,7 +15,7 @@ public class AircraftLookupModel
{
private readonly AircraftLookupManager _lookupManager;

public AircraftLookupModel(TrackerApplicationSettings settings)
public AircraftLookupModel(ITrackerLogger logger, TrackerApplicationSettings settings)
{
// Create a database context
var context = new BaseStationReaderDbContextFactory().CreateDbContext(Array.Empty<string>());
Expand All @@ -31,8 +32,8 @@ public AircraftLookupModel(TrackerApplicationSettings settings)

// Create the API wrappers
var client = TrackerHttpClient.Instance;
var airlinesApi = new AirLabsAirlinesApi(client, airlinesUrl, key);
var aircraftApi = new AirLabsAircraftApi(client, aircraftUrl, key);
var airlinesApi = new AirLabsAirlinesApi(logger, client, airlinesUrl, key);
var aircraftApi = new AirLabsAircraftApi(logger, client, aircraftUrl, key);

// Finally, create a lookup manager
_lookupManager = new AircraftLookupManager(airlinesManager, detailsManager, modelsManager, airlinesApi, aircraftApi);
Expand Down
37 changes: 37 additions & 0 deletions src/BaseStationReader.UI/Models/LiveViewModel.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using BaseStationReader.Entities.Config;
using BaseStationReader.Entities.Events;
using BaseStationReader.Entities.Expressions;
using BaseStationReader.Entities.Interfaces;
using BaseStationReader.Entities.Logging;
using BaseStationReader.Entities.Tracking;
using BaseStationReader.Logic.Database;
using BaseStationReader.Logic.Tracking;
Expand All @@ -14,6 +16,7 @@ namespace BaseStationReader.UI.Models
{
public class LiveViewModel
{
private ITrackerLogger? _logger = null;
private ITrackerWrapper? _wrapper = null;

public ObservableCollection<Aircraft> TrackedAircraft { get; private set; } = new();
Expand All @@ -27,8 +30,12 @@ public class LiveViewModel
/// <param name="settings"></param>
public void Initialise(ITrackerLogger logger, TrackerApplicationSettings settings)
{
_logger = logger;
_wrapper = new TrackerWrapper(logger, settings);
_wrapper.Initialise();
_wrapper.AircraftAdded += OnAircraftAdded;
_wrapper.AircraftUpdated += OnAircraftUpdated;
_wrapper.AircraftRemoved += OnAircraftRemoved;
}

/// <summary>
Expand Down Expand Up @@ -84,5 +91,35 @@ public void Refresh()
// Update the observable collection from the filtered aircraft list
TrackedAircraft = new ObservableCollection<Aircraft>(aircraft);
}

/// <summary>
/// Handle the event raised when a new aircraft is detected
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnAircraftAdded(object? sender, AircraftNotificationEventArgs e)
{
_logger!.LogMessage(Severity.Info, $"Added new aircraft {e.Aircraft.Address}");
}

/// <summary>
/// Handle the event raised when a new aircraft is updated
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnAircraftUpdated(object? sender, AircraftNotificationEventArgs e)
{
_logger!.LogMessage(Severity.Debug, $"Updated aircraft {e.Aircraft.Address}");
}

/// <summary>
/// Handle the event raised when a new aircraft is removed
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnAircraftRemoved(object? sender, AircraftNotificationEventArgs e)
{
_logger!.LogMessage(Severity.Debug, $"Removed aircraft {e.Aircraft.Address}");
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using BaseStationReader.Entities.Config;
using BaseStationReader.Entities.Interfaces;
using BaseStationReader.Entities.Lookup;
using BaseStationReader.UI.Models;
using ReactiveUI;
Expand All @@ -12,10 +13,10 @@ public class AircraftLookupWindowViewModel : AircraftLookupCriteria

public ReactiveCommand<Unit, AircraftLookupCriteria?> CloseCommand { get; private set; }

public AircraftLookupWindowViewModel(TrackerApplicationSettings settings, AircraftLookupCriteria? initialValues)
public AircraftLookupWindowViewModel(ITrackerLogger logger, TrackerApplicationSettings settings, AircraftLookupCriteria? initialValues)
{
// Set up the aircraft lookup model
_aircraftLookup = new AircraftLookupModel(settings);
_aircraftLookup = new AircraftLookupModel(logger, settings);

// Populate from the initial values, if supplied
Address = initialValues?.Address;
Expand Down
13 changes: 8 additions & 5 deletions src/BaseStationReader.UI/ViewModels/MainWindowViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ public class MainWindowViewModel : ViewModelBase
/// </summary>
public TrackerApplicationSettings? Settings { get; set; }

/// <summary>
/// Logging provider
/// </summary>
public ITrackerLogger? Logger { get; set; }

/// <summary>
/// True if the tracker is actively tracking
/// </summary>
Expand Down Expand Up @@ -119,7 +124,7 @@ public MainWindowViewModel()
ShowAircraftLookupDialog = new Interaction<AircraftLookupWindowViewModel, AircraftLookupCriteria?>();
ShowAircraftLookupCommand = ReactiveCommand.CreateFromTask(async () =>
{
var dialogViewModel = new AircraftLookupWindowViewModel(Settings!, AircraftLookupCriteria);
var dialogViewModel = new AircraftLookupWindowViewModel(Logger!, Settings!, AircraftLookupCriteria);
var result = await ShowAircraftLookupDialog.Handle(dialogViewModel);
return result;
});
Expand All @@ -146,10 +151,8 @@ public MainWindowViewModel()
/// <summary>
/// Initialise the tracker
/// </summary>
/// <param name="logger"></param>
/// <param name="settings"></param>
public void InitialiseTracker(ITrackerLogger logger, TrackerApplicationSettings settings)
=> _liveView.Initialise(logger, settings);
public void InitialiseTracker()
=> _liveView.Initialise(Logger!, Settings!);

/// <summary>
/// Start the tracker
Expand Down
Loading

0 comments on commit bab92b3

Please sign in to comment.