a0bf6c15f4
Resolves #52 This Pull Request introduces the **NexusSearchBox** search feature with premium unified styling, implements a robust **dynamic Qdrant collection auto-provisioning and batch-vector ingestion pipeline**, integrates a unified **Serilog logging infrastructure** for the Blazor Hybrid environment (MAUI), and resolves the **401 Unauthorized API header propagation error** inside mobile builds. ### 🚀 Key Implementations #### 1. Premium `NexusSearchBox` & Semantic Search UI * **NexusSearchBox Component:** Created an elegant search-as-you-type search box with smooth key navigation, quick-clearing, and seamless dynamic styling. * **Unified Aesthetics:** Refactored the search box isolated styling to align perfectly with the dashboard's design system using glassmorphism, `--nexus-neon` token gradients, and smooth pulse/fade animations. * **Semantic Search Integration:** Integrated semantic search query dispatching (`SearchLibrarySemanticallyQuery`) and wired up navigation seamlessly through the updated `ReaderNavigationService`. * **Tests Hardening:** Added/adapted query assertions in `QueryTests.cs` to guarantee safe parameterization and error boundary mapping. #### 2. Qdrant Collection Provisioning & Vector Ingestion * **Dynamic Auto-Provisioning:** Implemented dynamic checking and lazy-creation of the `knowledge_units` collection using 768 dimensions and Cosine distance. * **High-Performance Ingestion:** Optimized `ProcessKnowledgeUnitsAsync` with high-performance batch embedding generation using `_embeddingGenerator` and deterministic MD5 GUIDs for stable, duplicate-free upsertion. * **Database Cache Clear Sync:** Integrated Qdrant collection deletion in `ClearCacheAsync` to ensure absolute consistency between the PostgreSQL database cache and vector database indices. #### 3. Cross-Platform MAUI Logging (Serilog Infrastructure) * **Serilog Integration:** Configured cross-platform Serilog routing in `SerilogConfiguration.cs`, streaming diagnostic logs safely across native platforms and the Blazor Webview container. * **Interop Bridge:** Built `BlazorLoggingBridge.cs` to capture web console messages and pipe them directly to the native host logger. * **Demo Interface:** Added an interactive `SerilogDemo.razor` sandbox under Pages. #### 4. Resolving 401 Load Errors (Authentication Handler Flow) * **Authentication Header Handler:** Implemented the `MobileAuthenticationHeaderHandler` to correctly extract, validate, and inject bearer JWT tokens into outbound API requests. * **Configuration-based API Host:** Structured standard API URI routing to use clean configuration bindings in `appsettings.json`. --- ### 🧪 Verification & Build Status * Run `dotnet build` from the solution root: Successfully compiled the full multi-targeted solution (`Liczba błędów: 0`). * All unit and integration tests successfully executed and verified (`dotnet test`). --------- Co-authored-by: Marek Jasiński <jasins.marek@gmail.com> Co-authored-by: Marek Jaisński <jasins.marek@gmail.com> Reviewed-on: #51 Co-authored-by: Antigravity <antigravity@google.com> Co-committed-by: Antigravity <antigravity@google.com>
107 lines
3.6 KiB
C#
107 lines
3.6 KiB
C#
using Microsoft.Extensions.Logging;
|
|
using Serilog;
|
|
using Serilog.Core;
|
|
using Serilog.Events;
|
|
using Serilog.Formatting;
|
|
using Serilog.Formatting.Display;
|
|
|
|
namespace NexusReader.Maui.Infrastructure.Logging;
|
|
|
|
public static class SerilogConfiguration
|
|
{
|
|
private const string OutputTemplate =
|
|
"[{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz}] [{Level:u3}] [ThreadId: {ThreadId}] [{SourceContext}] {Message:lj}{NewLine}{Exception}";
|
|
|
|
public static MauiAppBuilder RegisterLogging(this MauiAppBuilder builder)
|
|
{
|
|
// 1. Ensure logs directory exists in secure sandbox
|
|
var logDir = Path.Combine(Microsoft.Maui.Storage.FileSystem.AppDataDirectory, "logs");
|
|
if (!Directory.Exists(logDir))
|
|
{
|
|
Directory.CreateDirectory(logDir);
|
|
}
|
|
var logPath = Path.Combine(logDir, "log-.txt");
|
|
|
|
// 2. Inject sandboxed log path dynamically into configuration provider
|
|
builder.Configuration["Serilog:WriteTo:0:Args:configure:0:Args:path"] = logPath;
|
|
|
|
// 3. Configure Serilog Logger Configuration using App Configuration settings
|
|
var loggerConfig = new LoggerConfiguration()
|
|
.ReadFrom.Configuration(builder.Configuration)
|
|
.Enrich.With(new ThreadIdEnricher());
|
|
|
|
// 4. Platform-specific and environment-specific sinks
|
|
#if ANDROID
|
|
// Direct Native Android Logcat Sink (JNI bindings for native diagnostics)
|
|
loggerConfig.WriteTo.Sink(
|
|
new AndroidLogcatSink(new MessageTemplateTextFormatter(OutputTemplate, null)),
|
|
restrictedToMinimumLevel: LogEventLevel.Debug);
|
|
#endif
|
|
|
|
// 5. Initialize the static Serilog Log
|
|
Log.Logger = loggerConfig.CreateLogger();
|
|
|
|
// 6. Connect Serilog to Microsoft.Extensions.Logging
|
|
builder.Logging.ClearProviders();
|
|
builder.Logging.AddSerilog(dispose: true);
|
|
|
|
return builder;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// A custom self-contained thread enricher to avoid unnecessary NuGet packages.
|
|
/// </summary>
|
|
internal sealed class ThreadIdEnricher : ILogEventEnricher
|
|
{
|
|
public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
|
|
{
|
|
logEvent.AddPropertyIfAbsent(propertyFactory.CreateProperty("ThreadId", Environment.CurrentManagedThreadId));
|
|
}
|
|
}
|
|
|
|
#if ANDROID
|
|
/// <summary>
|
|
/// A high-performance, direct Android Logcat Sink utilizing native Android APIs.
|
|
/// </summary>
|
|
internal sealed class AndroidLogcatSink : ILogEventSink
|
|
{
|
|
private readonly ITextFormatter _formatter;
|
|
private const string Tag = "NexusReader";
|
|
|
|
public AndroidLogcatSink(ITextFormatter formatter)
|
|
{
|
|
_formatter = formatter ?? throw new ArgumentNullException(nameof(formatter));
|
|
}
|
|
|
|
public void Emit(LogEvent logEvent)
|
|
{
|
|
using var writer = new StringWriter();
|
|
_formatter.Format(logEvent, writer);
|
|
var message = writer.ToString().Trim();
|
|
|
|
switch (logEvent.Level)
|
|
{
|
|
case LogEventLevel.Verbose:
|
|
Android.Util.Log.Verbose(Tag, message);
|
|
break;
|
|
case LogEventLevel.Debug:
|
|
Android.Util.Log.Debug(Tag, message);
|
|
break;
|
|
case LogEventLevel.Information:
|
|
Android.Util.Log.Info(Tag, message);
|
|
break;
|
|
case LogEventLevel.Warning:
|
|
Android.Util.Log.Warn(Tag, message);
|
|
break;
|
|
case LogEventLevel.Error:
|
|
Android.Util.Log.Error(Tag, message);
|
|
break;
|
|
case LogEventLevel.Fatal:
|
|
Android.Util.Log.Wtf(Tag, message);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
#endif
|