More logger improvements (#58)

* fix

* fix

---------

Co-authored-by: j92580498-max <j92580498-max@users.noreply.github.com>
This commit is contained in:
j92580498-max
2026-07-11 17:34:49 +03:00
committed by GitHub
parent 65a40773fa
commit ef74680167
4 changed files with 222 additions and 0 deletions

View File

@@ -32,4 +32,18 @@ SPDX-License-Identifier: GPL-2.0-or-later
<DebugType>none</DebugType> <DebugType>none</DebugType>
<DebugSymbols>false</DebugSymbols> <DebugSymbols>false</DebugSymbols>
</PropertyGroup> </PropertyGroup>
<!-- Build provenance surfaced by SharpEmu.Logging.BuildInfo as a banner at the
top of the log. Populated from GitHub Actions environment variables when
building in CI; empty locally. -->
<ItemGroup>
<AssemblyMetadata Include="SharpEmu.BuildConfiguration" Value="$(Configuration)" />
<AssemblyMetadata Condition="'$(GITHUB_SHA)' != ''" Include="SharpEmu.BuildSha" Value="$(GITHUB_SHA)" />
<AssemblyMetadata Condition="'$(GITHUB_REF_NAME)' != ''" Include="SharpEmu.BuildBranch" Value="$(GITHUB_REF_NAME)" />
<AssemblyMetadata Condition="'$(GITHUB_REF)' != ''" Include="SharpEmu.BuildRef" Value="$(GITHUB_REF)" />
<AssemblyMetadata Condition="'$(GITHUB_EVENT_NAME)' != ''" Include="SharpEmu.BuildEventName" Value="$(GITHUB_EVENT_NAME)" />
<AssemblyMetadata Condition="'$(GITHUB_REPOSITORY)' != ''" Include="SharpEmu.BuildRepository" Value="$(GITHUB_REPOSITORY)" />
<AssemblyMetadata Condition="'$(GITHUB_SERVER_URL)' != ''" Include="SharpEmu.BuildServerUrl" Value="$(GITHUB_SERVER_URL)" />
<AssemblyMetadata Condition="'$(GITHUB_RUN_ID)' != ''" Include="SharpEmu.BuildRunId" Value="$(GITHUB_RUN_ID)" />
</ItemGroup>
</Project> </Project>

View File

@@ -76,6 +76,8 @@ internal static partial class Program
SharpEmuLog.MinimumLevel = logLevel; SharpEmuLog.MinimumLevel = logLevel;
Log.Info(BuildInfo.Banner);
ebootPath = Path.GetFullPath(ebootPath); ebootPath = Path.GetFullPath(ebootPath);
Console.Error.WriteLine($"[DEBUG] Full path: {ebootPath}"); Console.Error.WriteLine($"[DEBUG] Full path: {ebootPath}");

View File

@@ -16,6 +16,7 @@ using System.Buffers.Binary;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.IO;
namespace SharpEmu.Core.Runtime; namespace SharpEmu.Core.Runtime;
@@ -141,6 +142,7 @@ public sealed class SharpEmuRuntime : ISharpEmuRuntime
var image = LoadImage(normalizedEbootPath); var image = LoadImage(normalizedEbootPath);
VideoOutExports.ConfigureApplicationInfo(image.Title, image.TitleId, image.Version); VideoOutExports.ConfigureApplicationInfo(image.Title, image.TitleId, image.Version);
SaveDataExports.ConfigureApplicationInfo(image.TitleId); SaveDataExports.ConfigureApplicationInfo(image.TitleId);
LogAppBundleInfo(normalizedEbootPath, image);
RegisterLoadedModule(normalizedEbootPath, image, isMain: true, isSystemModule: false); RegisterLoadedModule(normalizedEbootPath, image, isMain: true, isSystemModule: false);
KernelRuntimeCompatExports.ConfigureProcessProcParamAddress(image.ProcParamAddress); KernelRuntimeCompatExports.ConfigureProcessProcParamAddress(image.ProcParamAddress);
Log.Info($"Entry: 0x{image.EntryPoint:X16}"); Log.Info($"Entry: 0x{image.EntryPoint:X16}");
@@ -357,6 +359,66 @@ public sealed class SharpEmuRuntime : ISharpEmuRuntime
return result; return result;
} }
private static void LogAppBundleInfo(string ebootPath, SelfImage image)
{
var executableName = Path.GetFileName(ebootPath);
if (string.IsNullOrWhiteSpace(executableName))
{
executableName = "eboot.bin";
}
var displayName = string.IsNullOrWhiteSpace(image.Title) ? "(unknown)" : image.Title!.Trim();
var titleId = string.IsNullOrWhiteSpace(image.TitleId) ? "(unknown)" : image.TitleId!.Trim();
var version = string.IsNullOrWhiteSpace(image.Version) ? "(unknown)" : image.Version!.Trim();
var contentId = ResolveContentId(Path.GetDirectoryName(ebootPath)) ?? "(unknown)";
var builder = new StringBuilder();
builder.AppendLine("App bundle info:");
builder.AppendLine($"- Display name: {displayName}");
builder.AppendLine($"- Version: {version}");
builder.AppendLine($"- Title ID: {titleId}");
builder.AppendLine($"- Content ID: {contentId}");
builder.AppendLine($"- Executable: {executableName}");
builder.Append("- Platform: PlayStation 5");
Log.Info(builder.ToString());
}
private static string? ResolveContentId(string? bundleRoot)
{
if (string.IsNullOrEmpty(bundleRoot))
{
return null;
}
foreach (var candidate in new[]
{
Path.Combine(bundleRoot, "sce_sys", "param.json"),
Path.Combine(bundleRoot, "param.json"),
})
{
if (!File.Exists(candidate))
{
continue;
}
try
{
using var doc = System.Text.Json.JsonDocument.Parse(File.ReadAllBytes(candidate));
if (doc.RootElement.TryGetProperty("contentId", out var contentId))
{
return contentId.GetString();
}
}
catch (Exception ex) when (ex is IOException or System.Text.Json.JsonException)
{
}
break;
}
return null;
}
private static App0BindingScope? BindApp0Root(string normalizedEbootPath) private static App0BindingScope? BindApp0Root(string normalizedEbootPath)
{ {
const string app0VariableName = "SHARPEMU_APP0_DIR"; const string app0VariableName = "SHARPEMU_APP0_DIR";

View File

@@ -0,0 +1,144 @@
// Copyright (C) 2026 SharpEmu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
using System.Reflection;
namespace SharpEmu.Logging;
/// <summary>
/// Build provenance for the running emulator, populated at compile time from
/// GitHub Actions environment variables via <c>[AssemblyMetadata]</c> and
/// surfaced as a touchHLE-style banner at the top of the log.
/// </summary>
public static class BuildInfo
{
private const string ProjectUrl = "https://github.com/par274/sharpemu";
private const string CanonicalRepository = "par274/sharpemu";
/// <summary>Short commit hash the build was produced from, or <c>null</c>.</summary>
public static string? CommitSha { get; }
/// <summary>Branch the build was produced from, or <c>null</c>.</summary>
public static string? Branch { get; }
/// <summary>Repository slug (<c>owner/name</c>) the build came from, or <c>null</c>.</summary>
public static string? Repository { get; }
/// <summary>URL of the GitHub Actions workflow run that produced the build, or <c>null</c>.</summary>
public static string? WorkflowRunUrl { get; }
/// <summary>Build configuration (e.g. <c>Debug</c> or <c>Release</c>), or <c>null</c>.</summary>
public static string? Configuration { get; }
/// <summary>
/// Whether this build is an official release: a Release-configuration CI build
/// from the canonical repository, produced by a push to <c>main</c> or a manual
/// workflow dispatch (matching the CI <c>release</c> job). All other builds
/// (pull requests, forks, feature branches, and local/Debug builds) are
/// considered unofficial.
/// </summary>
public static bool IsOfficialRelease { get; }
static BuildInfo()
{
var metadata = ReadMetadata();
CommitSha = Normalize(metadata.GetValueOrDefault("SharpEmu.BuildSha"));
if (CommitSha is { Length: > 7 })
{
CommitSha = CommitSha[..7];
}
Branch = Normalize(metadata.GetValueOrDefault("SharpEmu.BuildBranch"));
Repository = Normalize(metadata.GetValueOrDefault("SharpEmu.BuildRepository"));
Configuration = Normalize(metadata.GetValueOrDefault("SharpEmu.BuildConfiguration"));
var serverUrl = Normalize(metadata.GetValueOrDefault("SharpEmu.BuildServerUrl"));
var runId = Normalize(metadata.GetValueOrDefault("SharpEmu.BuildRunId"));
if (serverUrl is not null && Repository is not null && runId is not null)
{
WorkflowRunUrl = $"{serverUrl.TrimEnd('/')}/{Repository}/actions/runs/{runId}";
}
var eventName = Normalize(metadata.GetValueOrDefault("SharpEmu.BuildEventName"));
var gitRef = Normalize(metadata.GetValueOrDefault("SharpEmu.BuildRef"));
var isReleaseConfig = string.Equals(Configuration, "Release", StringComparison.OrdinalIgnoreCase);
var isCanonicalRepo = string.Equals(Repository, CanonicalRepository, StringComparison.OrdinalIgnoreCase);
var isReleaseTrigger =
string.Equals(eventName, "workflow_dispatch", StringComparison.OrdinalIgnoreCase) ||
(string.Equals(eventName, "push", StringComparison.OrdinalIgnoreCase) &&
string.Equals(gitRef, "refs/heads/main", StringComparison.OrdinalIgnoreCase));
IsOfficialRelease = isReleaseConfig && isCanonicalRepo && isReleaseTrigger && CommitSha is not null;
}
/// <summary>
/// The multi-line banner, e.g.
/// <code>
/// SharpEmu UNOFFICIAL f11ac59 — https://github.com/par274/sharpemu
///
/// Built from branch "main" of "par274/sharpemu" by GitHub Actions workflow run https://github.com/par274/sharpemu/actions/runs/123.
/// </code>
/// Official release builds drop the <c>UNOFFICIAL</c> tag. Falls back to a
/// local-build line when no CI provenance is present.
/// </summary>
public static string Banner
{
get
{
string version;
if (CommitSha is null)
{
version = "UNOFFICIAL";
}
else if (IsOfficialRelease)
{
version = CommitSha;
}
else
{
version = $"UNOFFICIAL {CommitSha}";
}
var header = $"SharpEmu {version} — {ProjectUrl}";
if (Branch is null || Repository is null || WorkflowRunUrl is null)
{
return $"{header}{Environment.NewLine}{Environment.NewLine}Local build (not produced by CI).";
}
return $"{header}{Environment.NewLine}{Environment.NewLine}" +
$"Built from branch \"{Branch}\" of \"{Repository}\" by GitHub Actions workflow run {WorkflowRunUrl}.";
}
}
private static Dictionary<string, string> ReadMetadata()
{
var result = new Dictionary<string, string>(StringComparer.Ordinal);
var assemblies = new[] { Assembly.GetEntryAssembly(), typeof(BuildInfo).Assembly };
foreach (var assembly in assemblies)
{
if (assembly is null)
{
continue;
}
foreach (var attribute in assembly.GetCustomAttributes<AssemblyMetadataAttribute>())
{
if (attribute.Key.StartsWith("SharpEmu.Build", StringComparison.Ordinal) &&
!result.ContainsKey(attribute.Key) &&
attribute.Value is not null)
{
result[attribute.Key] = attribute.Value;
}
}
}
return result;
}
private static string? Normalize(string? value) =>
string.IsNullOrWhiteSpace(value) ? null : value.Trim();
}