Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,6 @@ src/UltimatePDF_ExternalLogic.E2ETests/appsettings.local.json

# IDE launch profiles
src/**/Properties/launchSettings.json

# AI working folder
specs/
4 changes: 2 additions & 2 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ This component operates within ODC's external logic environment, subject to:

## Deployment

The library is packaged as a ZIP file containing compiled .NET 8.0 binaries for linux-x64 runtime. Generate the package by running:
The library is packaged as a ZIP file containing compiled .NET 10.0 binaries for linux-x64 runtime. Generate the package by running:

```bash
.\generate_upload_package.ps1
Expand All @@ -132,7 +132,7 @@ Companion OutSystems modules in the `oml/` directory provide client-side acceler

## Technology Stack

- **.NET 8.0:** Target framework for ODC external logic
- **.NET 10.0:** Target framework for ODC external logic
- **PuppeteerSharp:** Browser automation library wrapping Chromium DevTools Protocol
- **HeadlessChromium.Puppeteer.Lambda.Dotnet:** Provides Chromium binaries compatible with AWS Lambda (ODC infrastructure)
- **PDFsharp 6.2.0:** PDF manipulation for merging layers (backgrounds, headers, footers)
Expand Down
8 changes: 4 additions & 4 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co

## Overview

UltimatePDF-ExternalLogic is an OutSystems Developer Cloud (ODC) external logic component that generates PDFs from web pages using Chromium's rendering engine. The code is written in C# targeting .NET 8.0 and runs within ODC's managed infrastructure.
UltimatePDF-ExternalLogic is an OutSystems Developer Cloud (ODC) external logic component that generates PDFs from web pages using Chromium's rendering engine. The code is written in C# targeting .NET 10.0 and runs within ODC's managed infrastructure.

For system architecture and design patterns, see [ARCHITECTURE.md](./ARCHITECTURE.md). For development workflow and contribution guidelines, see [CONTRIBUTING.md](./CONTRIBUTING.md).

Expand Down Expand Up @@ -143,10 +143,10 @@ See `LayoutPrintPipeline/Pipeline.cs` methods (`MergeBackground`, `MergeHeaders`

## Technology Stack

- **.NET 8.0** - Target framework for ODC external logic
- **.NET 10.0** - Target framework for ODC external logic
- **PuppeteerSharp** - Browser automation via Chrome DevTools Protocol
- **HeadlessChromium.Puppeteer.Lambda.Dotnet** (v1.1.0.97) - Chromium binaries for AWS Lambda (ODC infrastructure)
- **PDFsharp** (v6.2.0) - PDF layer composition
- **HeadlessChromium.Puppeteer.Dotnet.OS.Fork** (v1.1.1.1) - Chromium binaries for AWS Lambda (ODC infrastructure)
- **PDFsharp** (v6.2.4) - PDF layer composition
- **OutSystems.ExternalLibraries.SDK** (v1.5.0) - ODC external logic framework

## Additional Resources
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
Expand All @@ -18,7 +18,7 @@
<PackageReference Include="Microsoft.Extensions.Configuration" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="8.0.0" />
<PackageReference Include="PDFsharp" Version="6.2.0" />
<PackageReference Include="PDFsharp" Version="6.2.4" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
Expand All @@ -12,7 +12,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="PDFsharp" Version="6.2.0" />
<PackageReference Include="PDFsharp" Version="6.2.4" />
<PackageReference Include="xunit.v3.assert" Version="3.2.2" />
</ItemGroup>

Expand Down
2 changes: 1 addition & 1 deletion src/UltimatePDF_ExternalLogic.UnitTests/PipelineTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ private static Mock<IPage> BuildPageMock(Pipeline.LayoutPrint[] layouts) {
mock.Setup(p => p.EvaluateFunctionAsync<Pipeline.LayoutPrint[]>(It.IsAny<string>(), It.IsAny<object[]>()))
.ReturnsAsync(layouts);
mock.Setup(p => p.EvaluateFunctionAsync(It.IsAny<string>(), It.IsAny<object[]>()))
.ReturnsAsync(JValue.CreateNull());
.Returns(Task.CompletedTask);
mock.Setup(p => p.PdfDataAsync(It.IsAny<PdfOptions>()))
.ReturnsAsync(PdfFactory.CreateMinimal());
return mock;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
Expand Down
28 changes: 28 additions & 0 deletions src/UltimatePDF_ExternalLogic/Management/Troubleshooting/Logger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@ public class Logger {
private readonly ILogger logger;
private readonly ICollection<LogAttachment> attachments;
private readonly ICollection<CustomLoggerFactory> loggerFactories;
private readonly StringBuilder executionLog;
private readonly bool attachFilesLogs;

private Logger() {
logger = NullLogger<Logger>.Instance;
attachments = new List<LogAttachment>(6);
loggerFactories = new List<CustomLoggerFactory>(1);
executionLog = new StringBuilder();
}

protected Logger(ILogger logger, bool attachFilesLogs) : this() {
Expand All @@ -42,25 +44,39 @@ public void Log(string message) {
}

public virtual void Error(Exception? e, string? message, params object?[] args) {
AppendToExecutionLog(LogLevel.Error, message, e);
logger.LogError(e, message, args);
}

public virtual void Error(string message) {
AppendToExecutionLog(LogLevel.Error, message);
logger.LogError(message);
}

public virtual void Warning(string message) {
AppendToExecutionLog(LogLevel.Warning, message);
logger.LogWarning(message);
}

public virtual void Warning(string? message, params object?[] args) {
AppendToExecutionLog(LogLevel.Warning, message);
logger.LogWarning(message, args);
}

public virtual void Log(LogLevel level, string? message, params object?[] args) {
AppendToExecutionLog(level, message);
logger.Log(level, message, args);
}

private void AppendToExecutionLog(LogLevel level, string? message, Exception? exception = null) {
lock (executionLog) {
executionLog.AppendLine($"[{DateTime.UtcNow:o}] [{level}] - {message}");
if (exception != null) {
executionLog.AppendLine(exception.ToString());
}
}
}

public void Log(string message, bool condition) {
if (condition) {
Log(message);
Expand Down Expand Up @@ -89,13 +105,25 @@ public virtual byte[] GetZipFile() {

using (var zip = new ZipArchive(stream, ZipArchiveMode.Create, true))
{
AddExecutionLogToZip(zip);
AddAttachmentsToZip(zip);
AddCustomLoggersToZip(zip);
}

return stream.ToArray();
}

private void AddExecutionLogToZip(ZipArchive zip) {
if (executionLog.Length == 0) {
return;
}

var entry = zip.CreateEntry("execution.txt");
using var stream = entry.Open();
using var writer = new StreamWriter(stream, Encoding.UTF8);
writer.Write(executionLog.ToString());
}

private void AddAttachmentsToZip(ZipArchive zip) {
foreach (var attachment in attachments) {
var attachmentEntry = zip.CreateEntry(attachment.filename);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>

Expand All @@ -10,9 +10,9 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="HeadlessChromium.Puppeteer.Lambda.Dotnet" Version="1.1.0.97" />
<PackageReference Include="HeadlessChromium.Puppeteer.Dotnet.OS.Fork" Version="1.1.1.1" />
<PackageReference Include="OutSystems.ExternalLibraries.SDK" Version="1.5.0" />
<PackageReference Include="PDFsharp" Version="6.2.0" />
<PackageReference Include="PDFsharp" Version="6.2.4" />
</ItemGroup>

<ItemGroup>
Expand Down