melon 🍉🍉🍉

This commit is contained in:
2025-12-11 23:16:16 +01:00
parent a2429cb920
commit 580349fc6b
45 changed files with 610 additions and 3752 deletions

3
.gitignore vendored
View File

@@ -1,2 +1,3 @@
/.vs /.vs
x64 bin
obj

22
Peak.sln Normal file
View File

@@ -0,0 +1,22 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.12.35506.116 d17.12
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Peak", "Peak\Peak.csproj", "{132011FB-CD98-4500-B7A7-B5BB0CD3BFA4}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{132011FB-CD98-4500-B7A7-B5BB0CD3BFA4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{132011FB-CD98-4500-B7A7-B5BB0CD3BFA4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{132011FB-CD98-4500-B7A7-B5BB0CD3BFA4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{132011FB-CD98-4500-B7A7-B5BB0CD3BFA4}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

550
Peak/Peak.csproj Normal file
View File

@@ -0,0 +1,550 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>disable</Nullable>
<RootNamespace>Peak</RootNamespace>
<LangVersion>default</LangVersion>
<IsPackable>false</IsPackable>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
<FileVersion>1.0.0.0</FileVersion>
<NeutralLanguage>en-US</NeutralLanguage>
<AssemblyName>Peak</AssemblyName>
<LangVersion>latest</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<Reference Include="Ashley.MeshSplitter">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Ashley.MeshSplitter.dll</HintPath>
</Reference>
<Reference Include="Assembly-CSharp-firstpass">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Assembly-CSharp-firstpass.dll</HintPath>
</Reference>
<Reference Include="Assembly-CSharp">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Assembly-CSharp.dll</HintPath>
</Reference>
<Reference Include="com.rlabrecque.steamworks.net">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\com.rlabrecque.steamworks.net.dll</HintPath>
</Reference>
<Reference Include="DemiLib">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\DemiLib.dll</HintPath>
</Reference>
<Reference Include="DOTween">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\DOTween.dll</HintPath>
</Reference>
<Reference Include="DOTweenPro">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\DOTweenPro.dll</HintPath>
</Reference>
<Reference Include="HBAO.Runtime">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\HBAO.Runtime.dll</HintPath>
</Reference>
<Reference Include="HBAO.Universal.Runtime">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\HBAO.Universal.Runtime.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="Photon3Unity3D">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Photon3Unity3D.dll</HintPath>
</Reference>
<Reference Include="PhotonChat">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\PhotonChat.dll</HintPath>
</Reference>
<Reference Include="PhotonRealtime">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\PhotonRealtime.dll</HintPath>
</Reference>
<Reference Include="PhotonUnityNetworking.Demos">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\PhotonUnityNetworking.Demos.dll</HintPath>
</Reference>
<Reference Include="PhotonUnityNetworking">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\PhotonUnityNetworking.dll</HintPath>
</Reference>
<Reference Include="PhotonUnityNetworking.Utilities">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\PhotonUnityNetworking.Utilities.dll</HintPath>
</Reference>
<Reference Include="PhotonVoice.API">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\PhotonVoice.API.dll</HintPath>
</Reference>
<Reference Include="PhotonVoice">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\PhotonVoice.dll</HintPath>
</Reference>
<Reference Include="PhotonVoice.PUN">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\PhotonVoice.PUN.dll</HintPath>
</Reference>
<Reference Include="pworld">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\pworld.dll</HintPath>
</Reference>
<Reference Include="sc.posteffects.runtime">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\sc.posteffects.runtime.dll</HintPath>
</Reference>
<Reference Include="Sirenix.OdinInspector.Attributes">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Sirenix.OdinInspector.Attributes.dll</HintPath>
</Reference>
<Reference Include="Sirenix.OdinInspector.Modules.Unity.Addressables">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Sirenix.OdinInspector.Modules.Unity.Addressables.dll</HintPath>
</Reference>
<Reference Include="Sirenix.OdinInspector.Modules.UnityLocalization">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Sirenix.OdinInspector.Modules.UnityLocalization.dll</HintPath>
</Reference>
<Reference Include="Sirenix.Serialization.Config">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Sirenix.Serialization.Config.dll</HintPath>
</Reference>
<Reference Include="Sirenix.Serialization">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Sirenix.Serialization.dll</HintPath>
</Reference>
<Reference Include="Sirenix.Utilities">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Sirenix.Utilities.dll</HintPath>
</Reference>
<Reference Include="Tayx.Graphy">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Tayx.Graphy.dll</HintPath>
</Reference>
<Reference Include="unity-websocket-sharp">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\unity-websocket-sharp.dll</HintPath>
</Reference>
<Reference Include="Unity.Addressables">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Unity.Addressables.dll</HintPath>
</Reference>
<Reference Include="Unity.AI.Navigation">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Unity.AI.Navigation.dll</HintPath>
</Reference>
<Reference Include="Unity.Animation.Rigging">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Unity.Animation.Rigging.dll</HintPath>
</Reference>
<Reference Include="Unity.Animation.Rigging.DocCodeExamples">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Unity.Animation.Rigging.DocCodeExamples.dll</HintPath>
</Reference>
<Reference Include="Unity.Burst">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Unity.Burst.dll</HintPath>
</Reference>
<Reference Include="Unity.Burst.Unsafe">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Unity.Burst.Unsafe.dll</HintPath>
</Reference>
<Reference Include="Unity.Cinemachine">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Unity.Cinemachine.dll</HintPath>
</Reference>
<Reference Include="Unity.Collections">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Unity.Collections.dll</HintPath>
</Reference>
<Reference Include="Unity.Collections.LowLevel.ILSupport">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Unity.Collections.LowLevel.ILSupport.dll</HintPath>
</Reference>
<Reference Include="Unity.InputSystem">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Unity.InputSystem.dll</HintPath>
</Reference>
<Reference Include="Unity.InputSystem.ForUI">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Unity.InputSystem.ForUI.dll</HintPath>
</Reference>
<Reference Include="Unity.InputSystem.RebindingUI">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Unity.InputSystem.RebindingUI.dll</HintPath>
</Reference>
<Reference Include="Unity.InternalAPIEngineBridge.013">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Unity.InternalAPIEngineBridge.013.dll</HintPath>
</Reference>
<Reference Include="Unity.Localization">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Unity.Localization.dll</HintPath>
</Reference>
<Reference Include="Unity.Mathematics">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Unity.Mathematics.dll</HintPath>
</Reference>
<Reference Include="Unity.MemoryProfiler">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Unity.MemoryProfiler.dll</HintPath>
</Reference>
<Reference Include="Unity.Multiplayer.Center.Common">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Unity.Multiplayer.Center.Common.dll</HintPath>
</Reference>
<Reference Include="Unity.Multiplayer.Playmode.Common.Runtime">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Unity.Multiplayer.Playmode.Common.Runtime.dll</HintPath>
</Reference>
<Reference Include="Unity.Multiplayer.Playmode">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Unity.Multiplayer.Playmode.dll</HintPath>
</Reference>
<Reference Include="Unity.Networking.Transport">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Unity.Networking.Transport.dll</HintPath>
</Reference>
<Reference Include="Unity.Profiling.Core">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Unity.Profiling.Core.dll</HintPath>
</Reference>
<Reference Include="Unity.Rendering.LightTransport.Runtime">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Unity.Rendering.LightTransport.Runtime.dll</HintPath>
</Reference>
<Reference Include="Unity.RenderPipeline.Universal.ShaderLibrary">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Unity.RenderPipeline.Universal.ShaderLibrary.dll</HintPath>
</Reference>
<Reference Include="Unity.RenderPipelines.Core.Runtime">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Unity.RenderPipelines.Core.Runtime.dll</HintPath>
</Reference>
<Reference Include="Unity.RenderPipelines.Core.Runtime.Shared">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Unity.RenderPipelines.Core.Runtime.Shared.dll</HintPath>
</Reference>
<Reference Include="Unity.RenderPipelines.Core.ShaderLibrary">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Unity.RenderPipelines.Core.ShaderLibrary.dll</HintPath>
</Reference>
<Reference Include="Unity.RenderPipelines.GPUDriven.Runtime">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Unity.RenderPipelines.GPUDriven.Runtime.dll</HintPath>
</Reference>
<Reference Include="Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary.dll</HintPath>
</Reference>
<Reference Include="Unity.RenderPipelines.Universal.2D.Runtime">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Unity.RenderPipelines.Universal.2D.Runtime.dll</HintPath>
</Reference>
<Reference Include="Unity.RenderPipelines.Universal.Config.Runtime">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Unity.RenderPipelines.Universal.Config.Runtime.dll</HintPath>
</Reference>
<Reference Include="Unity.RenderPipelines.Universal.Runtime">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Unity.RenderPipelines.Universal.Runtime.dll</HintPath>
</Reference>
<Reference Include="Unity.RenderPipelines.Universal.Shaders">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Unity.RenderPipelines.Universal.Shaders.dll</HintPath>
</Reference>
<Reference Include="Unity.ResourceManager">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Unity.ResourceManager.dll</HintPath>
</Reference>
<Reference Include="Unity.ScriptableBuildPipeline">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Unity.ScriptableBuildPipeline.dll</HintPath>
</Reference>
<Reference Include="Unity.Services.Authentication">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Unity.Services.Authentication.dll</HintPath>
</Reference>
<Reference Include="Unity.Services.Authentication.PlayerAccounts">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Unity.Services.Authentication.PlayerAccounts.dll</HintPath>
</Reference>
<Reference Include="Unity.Services.Core.Analytics">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Unity.Services.Core.Analytics.dll</HintPath>
</Reference>
<Reference Include="Unity.Services.Core.Components">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Unity.Services.Core.Components.dll</HintPath>
</Reference>
<Reference Include="Unity.Services.Core.Configuration">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Unity.Services.Core.Configuration.dll</HintPath>
</Reference>
<Reference Include="Unity.Services.Core.Device">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Unity.Services.Core.Device.dll</HintPath>
</Reference>
<Reference Include="Unity.Services.Core">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Unity.Services.Core.dll</HintPath>
</Reference>
<Reference Include="Unity.Services.Core.Environments">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Unity.Services.Core.Environments.dll</HintPath>
</Reference>
<Reference Include="Unity.Services.Core.Environments.Internal">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Unity.Services.Core.Environments.Internal.dll</HintPath>
</Reference>
<Reference Include="Unity.Services.Core.Internal">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Unity.Services.Core.Internal.dll</HintPath>
</Reference>
<Reference Include="Unity.Services.Core.Networking">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Unity.Services.Core.Networking.dll</HintPath>
</Reference>
<Reference Include="Unity.Services.Core.Registration">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Unity.Services.Core.Registration.dll</HintPath>
</Reference>
<Reference Include="Unity.Services.Core.Scheduler">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Unity.Services.Core.Scheduler.dll</HintPath>
</Reference>
<Reference Include="Unity.Services.Core.Telemetry">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Unity.Services.Core.Telemetry.dll</HintPath>
</Reference>
<Reference Include="Unity.Services.Core.Threading">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Unity.Services.Core.Threading.dll</HintPath>
</Reference>
<Reference Include="Unity.Services.Multiplayer">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Unity.Services.Multiplayer.dll</HintPath>
</Reference>
<Reference Include="Unity.Services.QoS">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Unity.Services.QoS.dll</HintPath>
</Reference>
<Reference Include="Unity.Services.Wire.Internal">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Unity.Services.Wire.Internal.dll</HintPath>
</Reference>
<Reference Include="Unity.Splines">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Unity.Splines.dll</HintPath>
</Reference>
<Reference Include="Unity.TextMeshPro">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Unity.TextMeshPro.dll</HintPath>
</Reference>
<Reference Include="Unity.Timeline">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Unity.Timeline.dll</HintPath>
</Reference>
<Reference Include="Unity.VisualEffectGraph.Runtime">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Unity.VisualEffectGraph.Runtime.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.AccessibilityModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.AccessibilityModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.AIModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.AIModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.AMDModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.AMDModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.AndroidJNIModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.AndroidJNIModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.AnimationModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.AnimationModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.ARModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.ARModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.AssetBundleModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.AssetBundleModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.AudioModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.AudioModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.ClothModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.ClothModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.ClusterInputModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.ClusterInputModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.ClusterRendererModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.ClusterRendererModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.ContentLoadModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.ContentLoadModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.CoreModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.CoreModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.CrashReportingModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.CrashReportingModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.DirectorModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.DirectorModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.DSPGraphModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.DSPGraphModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.GameCenterModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.GameCenterModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.GIModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.GIModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.GraphicsStateCollectionSerializerModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.GraphicsStateCollectionSerializerModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.GridModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.GridModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.HierarchyCoreModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.HierarchyCoreModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.HotReloadModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.HotReloadModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.ImageConversionModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.ImageConversionModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.IMGUIModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.IMGUIModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.InputForUIModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.InputForUIModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.InputLegacyModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.InputLegacyModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.InputModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.InputModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.JSONSerializeModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.JSONSerializeModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.LocalizationModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.LocalizationModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.MarshallingModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.MarshallingModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.MultiplayerModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.MultiplayerModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.NVIDIAModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.NVIDIAModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.ParticleSystemModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.ParticleSystemModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.PerformanceReportingModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.PerformanceReportingModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.Physics2DModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.Physics2DModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.PhysicsModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.PhysicsModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.PropertiesModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.PropertiesModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.RuntimeInitializeOnLoadManagerInitializerModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.RuntimeInitializeOnLoadManagerInitializerModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.ScreenCaptureModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.ScreenCaptureModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.ShaderVariantAnalyticsModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.ShaderVariantAnalyticsModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.SharedInternalsModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.SharedInternalsModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.SpriteMaskModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.SpriteMaskModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.SpriteShapeModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.SpriteShapeModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.StreamingModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.StreamingModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.SubstanceModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.SubstanceModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.SubsystemsModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.SubsystemsModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.TerrainModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.TerrainModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.TerrainPhysicsModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.TerrainPhysicsModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.TextCoreFontEngineModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.TextCoreFontEngineModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.TextCoreTextEngineModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.TextCoreTextEngineModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.TextRenderingModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.TextRenderingModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.TilemapModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.TilemapModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.TLSModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.TLSModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.UI">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.UI.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.UIElementsModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.UIElementsModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.UIModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.UIModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.UmbraModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.UmbraModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.UnityAnalyticsCommonModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.UnityAnalyticsCommonModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.UnityAnalyticsModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.UnityAnalyticsModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.UnityConnectModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.UnityConnectModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.UnityCurlModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.UnityCurlModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.UnityTestProtocolModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.UnityTestProtocolModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.UnityWebRequestAssetBundleModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.UnityWebRequestAssetBundleModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.UnityWebRequestAudioModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.UnityWebRequestAudioModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.UnityWebRequestModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.UnityWebRequestModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.UnityWebRequestTextureModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.UnityWebRequestTextureModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.UnityWebRequestWWWModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.UnityWebRequestWWWModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.VehiclesModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.VehiclesModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.VFXModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.VFXModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.VideoModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.VideoModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.VirtualTexturingModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.VirtualTexturingModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.VRModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.VRModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.WindModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.WindModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.XRModule">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityEngine.XRModule.dll</HintPath>
</Reference>
<Reference Include="UnityUIExtensions">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\UnityUIExtensions.dll</HintPath>
</Reference>
<Reference Include="websocket-sharp">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\websocket-sharp.dll</HintPath>
</Reference>
<Reference Include="Whinarn.UnityMeshSimplifier.Runtime">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Whinarn.UnityMeshSimplifier.Runtime.dll</HintPath>
</Reference>
<Reference Include="Zorro.AutoLOD">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Zorro.AutoLOD.dll</HintPath>
</Reference>
<Reference Include="Zorro.ControllerSupport">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Zorro.ControllerSupport.dll</HintPath>
</Reference>
<Reference Include="Zorro.Core.Runtime">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Zorro.Core.Runtime.dll</HintPath>
</Reference>
<Reference Include="Zorro.JiggleBones">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Zorro.JiggleBones.dll</HintPath>
</Reference>
<Reference Include="Zorro.PhotonUtility">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Zorro.PhotonUtility.dll</HintPath>
</Reference>
<Reference Include="Zorro.Settings.Runtime">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Zorro.Settings.Runtime.dll</HintPath>
</Reference>
<Reference Include="Zorro.UI.Runtime">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\PEAK_Data\Managed\Zorro.UI.Runtime.dll</HintPath>
</Reference>
<Reference Include="MelonLoader">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\MelonLoader\net35\MelonLoader.dll</HintPath>
</Reference>
<Reference Include="0Harmony">
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\PEAK\MelonLoader\net35\0Harmony.dll</HintPath>
</Reference>
</ItemGroup>
<PropertyGroup>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
</PropertyGroup>
<ItemGroup>
<Compile Include="PeakMenu.cs" />
<Compile Include="Speed.cs" />
</ItemGroup>
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
<Exec Command="COPY &quot;$(TargetPath)&quot; &quot;C:\Program Files (x86)\Steam\steamapps\common\PEAK\Mods&quot;" />
</Target>
</Project>

20
Peak/PeakMenu.cs Normal file
View File

@@ -0,0 +1,20 @@
using MelonLoader;
[assembly: MelonInfo(typeof(Peak.PeakMenu), "PeakMenu", "1.0.0", "KaseToatz")]
[assembly: MelonGame("LandCrab", "PEAK")]
namespace Peak
{
public class PeakMenu : MelonMod
{
public override void OnLateUpdate()
{
Character local = Character.localCharacter;
if (local != null)
{
local.refs.climbing.climbSpeedMod = 5F;
local.data.currentStamina = local.GetMaxStamina();
}
}
}
}

16
Peak/Speed.cs Normal file
View File

@@ -0,0 +1,16 @@
using HarmonyLib;
using System.Reflection;
[HarmonyPatch(typeof(CharacterMovement), "GetMovementForce")]
public static class Speed
{
private static readonly FieldInfo character = typeof(CharacterMovement).GetField("character", BindingFlags.NonPublic | BindingFlags.Instance);
public static void Postfix(CharacterMovement __instance, ref float __result)
{
if (ReferenceEquals(character.GetValue(__instance), Character.localCharacter))
{
__result *= 5F;
}
}
}

View File

@@ -1,28 +0,0 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.12.35506.116 d17.12
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PeakMenu", "PeakMenu\PeakMenu.vcxproj", "{AF72AD5F-FAC1-489C-A022-36C08515D36B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{AF72AD5F-FAC1-489C-A022-36C08515D36B}.Debug|x64.ActiveCfg = Debug|x64
{AF72AD5F-FAC1-489C-A022-36C08515D36B}.Debug|x64.Build.0 = Debug|x64
{AF72AD5F-FAC1-489C-A022-36C08515D36B}.Debug|x86.ActiveCfg = Debug|Win32
{AF72AD5F-FAC1-489C-A022-36C08515D36B}.Debug|x86.Build.0 = Debug|Win32
{AF72AD5F-FAC1-489C-A022-36C08515D36B}.Release|x64.ActiveCfg = Release|x64
{AF72AD5F-FAC1-489C-A022-36C08515D36B}.Release|x64.Build.0 = Release|x64
{AF72AD5F-FAC1-489C-A022-36C08515D36B}.Release|x86.ActiveCfg = Release|Win32
{AF72AD5F-FAC1-489C-A022-36C08515D36B}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@@ -1,156 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>17.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{af72ad5f-fac1-489c-a022-36c08515d36b}</ProjectGuid>
<RootNamespace>PeakMenu</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp20</LanguageStandard>
<AdditionalIncludeDirectories>C:\Users\raefb\Documents\GitHub\PeakMenu\PeakMenu\g3log;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="g3log\crashhandler_windows.cpp" />
<ClCompile Include="g3log\filesink.cpp" />
<ClCompile Include="g3log\g3log.cpp" />
<ClCompile Include="g3log\logcapture.cpp" />
<ClCompile Include="g3log\loglevels.cpp" />
<ClCompile Include="g3log\logmessage.cpp" />
<ClCompile Include="g3log\logworker.cpp" />
<ClCompile Include="g3log\stacktrace_windows.cpp" />
<ClCompile Include="g3log\time.cpp" />
<ClCompile Include="main.cpp" />
<ClCompile Include="pointers.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="common.hpp" />
<ClInclude Include="g3log\filesinkhelper.ipp" />
<ClInclude Include="g3log\g2log.hpp" />
<ClInclude Include="logger.hpp" />
<ClInclude Include="memory.hpp" />
<ClInclude Include="offsets.hpp" />
<ClInclude Include="pointers.hpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@@ -1,78 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
<Filter Include="Source Files\g3log">
<UniqueIdentifier>{06b8dc19-35a5-4810-9c1c-bc3255a43a94}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="main.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="g3log\crashhandler_windows.cpp">
<Filter>Source Files\g3log</Filter>
</ClCompile>
<ClCompile Include="g3log\filesink.cpp">
<Filter>Source Files\g3log</Filter>
</ClCompile>
<ClCompile Include="g3log\g3log.cpp">
<Filter>Source Files\g3log</Filter>
</ClCompile>
<ClCompile Include="g3log\logcapture.cpp">
<Filter>Source Files\g3log</Filter>
</ClCompile>
<ClCompile Include="g3log\loglevels.cpp">
<Filter>Source Files\g3log</Filter>
</ClCompile>
<ClCompile Include="g3log\logmessage.cpp">
<Filter>Source Files\g3log</Filter>
</ClCompile>
<ClCompile Include="g3log\logworker.cpp">
<Filter>Source Files\g3log</Filter>
</ClCompile>
<ClCompile Include="g3log\stacktrace_windows.cpp">
<Filter>Source Files\g3log</Filter>
</ClCompile>
<ClCompile Include="g3log\time.cpp">
<Filter>Source Files\g3log</Filter>
</ClCompile>
<ClCompile Include="pointers.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="common.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="g3log\filesinkhelper.ipp">
<Filter>Source Files\g3log</Filter>
</ClInclude>
<ClInclude Include="g3log\g2log.hpp">
<Filter>Source Files\g3log</Filter>
</ClInclude>
<ClInclude Include="logger.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="memory.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="pointers.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="offsets.hpp">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
</Project>

View File

@@ -1,15 +0,0 @@
#pragma once
#include <Windows.h>
#include <iostream>
#include <filesystem>
#include <fstream>
namespace peak
{
using namespace std::chrono_literals;
inline bool isRunning{true};
inline HMODULE hModule;
inline HANDLE mainThread{};
inline DWORD mainThreadId{};
}

View File

@@ -1,249 +0,0 @@
/** ==========================================================================
* 2011 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================*/
#if !(defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
#error "crashhandler_windows.cpp used but not on a windows system"
#endif
#include <process.h> // getpid
#include <windows.h>
#include <atomic>
#include <csignal>
#include <cstring>
#include <sstream>
#include "g3log/crashhandler.hpp"
#include "g3log/g3log.hpp"
#include "g3log/logcapture.hpp"
#include "g3log/stacktrace_windows.hpp"
#define getpid _getpid
namespace {
std::atomic<bool> gBlockForFatal{true};
LPTOP_LEVEL_EXCEPTION_FILTER g_previous_unexpected_exception_handler = nullptr;
#if !(defined(DISABLE_FATAL_SIGNALHANDLING))
thread_local bool g_installed_thread_signal_handler = false;
#endif
#if !(defined(DISABLE_VECTORED_EXCEPTIONHANDLING))
void* g_vector_exception_handler = nullptr;
#endif
// called for fatal signals SIGABRT, SIGFPE, SIGSEGV, SIGILL, SIGTERM
void signalHandler(int signal_number) {
using namespace g3::internal;
std::string dump = stacktrace::stackdump();
std::ostringstream fatal_stream;
fatal_stream << "\n***** Received fatal signal " << g3::internal::exitReasonName(g3::internal::FATAL_SIGNAL, signal_number);
fatal_stream << "(" << signal_number << ")\tPID: " << getpid() << std::endl;
LogCapture trigger(FATAL_SIGNAL, static_cast<g3::SignalType>(signal_number), dump.c_str());
trigger.stream() << fatal_stream.str();
// Trigger debug break point, if we're in debug. This breakpoint CAN cause a slowdown when it happens.
// Be patient. The "Debug" dialog should pop-up eventually if you doing it in Visual Studio.
// For fatal signals only, not exceptions.
// This is a way to tell the IDE (if in dev mode) that it can stop at this breakpoint
// Note that at this time the fatal log event with stack trace is NOT yet flushed to the logger
// This call will do nothing unless we're in DEBUG and "DEBUG_BREAK_AT_FATAL_SIGNAL" is enabled
// ref: g3log/Options.cmake
#if (!defined(NDEBUG) && defined(DEBUG_BREAK_AT_FATAL_SIGNAL))
__debugbreak();
#endif
} // scope exit - message sent to LogWorker, wait to die...
// Unhandled exception catching
LONG WINAPI exceptionHandling(EXCEPTION_POINTERS* info, const std::string& handler) {
std::string dump = stacktrace::stackdump(info);
std::ostringstream fatal_stream;
const g3::SignalType exception_code = info->ExceptionRecord->ExceptionCode;
fatal_stream << "\n***** " << handler << ": Received fatal exception " << g3::internal::exitReasonName(g3::internal::FATAL_EXCEPTION, exception_code);
fatal_stream << "\tPID: " << getpid() << std::endl;
const auto fatal_id = static_cast<g3::SignalType>(exception_code);
LogCapture trigger(g3::internal::FATAL_EXCEPTION, fatal_id, dump.c_str());
trigger.stream() << fatal_stream.str();
// FATAL Exception: It doesn't necessarily stop here. we pass on continue search
// if no one else will catch that then it's goodbye anyhow.
// The RISK here is if someone is catching this and returning "EXCEPTION_EXECUTE_HANDLER"
// but does not shutdown then the software will be running with g3log shutdown.
// .... However... this must be seen as a bug from standard handling of fatal exceptions
// https://msdn.microsoft.com/en-us/library/6wxdsc38.aspx
return EXCEPTION_CONTINUE_SEARCH;
}
// Unhandled exception catching
LONG WINAPI unexpectedExceptionHandling(EXCEPTION_POINTERS* info) {
g3::internal::restoreFatalHandlingToDefault();
return exceptionHandling(info, "Unexpected Exception Handler");
}
/// Setup through (Windows API) AddVectoredExceptionHandler
/// Ref: http://blogs.msdn.com/b/zhanli/archive/2010/06/25/c-tips-addvectoredexceptionhandler-addvectoredcontinuehandler-and-setunhandledexceptionfilter.aspx
#if !(defined(DISABLE_VECTORED_EXCEPTIONHANDLING))
LONG WINAPI vectorExceptionHandling(PEXCEPTION_POINTERS p) {
const g3::SignalType exception_code = p->ExceptionRecord->ExceptionCode;
if (false == stacktrace::isKnownException(exception_code)) {
// The unknown exception is ignored. Since it is not a Windows
// fatal exception generated by the OS we leave the
// responsibility to deal with this by the client software.
return EXCEPTION_CONTINUE_SEARCH;
} else {
g3::internal::restoreFatalHandlingToDefault();
return exceptionHandling(p, "Vectored Exception Handler");
}
}
#endif
} // end anonymous namespace
namespace g3 {
namespace internal {
// For windows exceptions this might ONCE be set to false, in case of a
// windows exceptions and not a signal
bool shouldBlockForFatalHandling() {
return gBlockForFatal;
}
/// Generate stackdump. Or in case a stackdump was pre-generated and
/// non-empty just use that one. i.e. the latter case is only for
/// Windows and test purposes
std::string stackdump(const char* dump) {
if (nullptr != dump && !std::string(dump).empty()) {
return {dump};
}
return stacktrace::stackdump();
}
/// string representation of signal ID or Windows exception id
std::string exitReasonName(const LEVELS& level, g3::SignalType fatal_id) {
if (level == g3::internal::FATAL_EXCEPTION) {
return stacktrace::exceptionIdToText(fatal_id);
}
switch (fatal_id) {
case SIGABRT:
return "SIGABRT";
break;
case SIGFPE:
return "SIGFPE";
break;
case SIGSEGV:
return "SIGSEGV";
break;
case SIGILL:
return "SIGILL";
break;
case SIGTERM:
return "SIGTERM";
break;
default:
std::ostringstream oss;
oss << "UNKNOWN SIGNAL(" << fatal_id << ")";
return oss.str();
}
}
// Triggered by g3log::LogWorker after receiving a FATAL trigger
// which is LOG(FATAL), CHECK(false) or a fatal signal our signalhandler caught.
// --- If LOG(FATAL) or CHECK(false) the signal_number will be SIGABRT
void exitWithDefaultSignalHandler(const LEVELS& level, g3::SignalType fatal_signal_id) {
restoreFatalHandlingToDefault();
// For windows exceptions we want to continue the possibility of
// exception handling now when the log and stacktrace are flushed
// to sinks. We therefore avoid to kill the process here. Instead
// it will be the exceptionHandling functions above that
// will let exception handling continue with: EXCEPTION_CONTINUE_SEARCH
if (g3::internal::FATAL_EXCEPTION == level) {
gBlockForFatal = false;
return;
}
// for a signal however, we exit through that fatal signal
const int signal_number = static_cast<int>(fatal_signal_id);
raise(signal_number);
}
// FYI: Concept of async-signal-safe operations does not exist on windows
// we stick to perror for lack of better alternatives.
size_t writeErrorMessage(const char* message) {
perror(message);
return std::strlen(message);
}
// Restore back to default fatal event handling
void restoreFatalHandlingToDefault() {
#if !(defined(DISABLE_FATAL_SIGNALHANDLING))
SetUnhandledExceptionFilter(g_previous_unexpected_exception_handler);
#if !(defined(DISABLE_VECTORED_EXCEPTIONHANDLING))
RemoveVectoredExceptionHandler(g_vector_exception_handler);
#endif
if (SIG_ERR == signal(SIGABRT, SIG_DFL))
internal::writeErrorMessage("signal - SIGABRT");
if (SIG_ERR == signal(SIGFPE, SIG_DFL))
internal::writeErrorMessage("signal - SIGABRT");
if (SIG_ERR == signal(SIGSEGV, SIG_DFL))
internal::writeErrorMessage("signal - SIGABRT");
if (SIG_ERR == signal(SIGILL, SIG_DFL))
internal::writeErrorMessage("signal - SIGABRT");
if (SIG_ERR == signal(SIGTERM, SIG_DFL))
internal::writeErrorMessage("signal - SIGABRT");
#endif
}
void installSignalHandler() {
g3::installSignalHandlerForThread();
}
} // namespace internal
/// SIGFPE, SIGILL, and SIGSEGV handling must be installed per thread
/// on Windows. This is automatically done if you do at least one LOG(...) call
/// you can also use this function call, per thread so make sure these three
/// fatal signals are covered in your thread (even if you don't do a LOG(...) call
void installSignalHandlerForThread() {
#if !(defined(DISABLE_FATAL_SIGNALHANDLING))
if (!g_installed_thread_signal_handler) {
g_installed_thread_signal_handler = true;
if (SIG_ERR == signal(SIGTERM, signalHandler))
internal::writeErrorMessage("signal - SIGTERM");
if (SIG_ERR == signal(SIGABRT, signalHandler))
internal::writeErrorMessage("signal - SIGABRT");
if (SIG_ERR == signal(SIGFPE, signalHandler))
internal::writeErrorMessage("signal - SIGFPE");
if (SIG_ERR == signal(SIGSEGV, signalHandler))
internal::writeErrorMessage("signal - SIGSEGV");
if (SIG_ERR == signal(SIGILL, signalHandler))
internal::writeErrorMessage("signal - SIGILL");
}
#endif
}
void installCrashHandler() {
internal::installSignalHandler();
g_previous_unexpected_exception_handler = SetUnhandledExceptionFilter(unexpectedExceptionHandling);
#if !(defined(DISABLE_VECTORED_EXCEPTIONHANDLING))
// const size_t kFirstExceptionHandler = 1;
// kFirstExceptionsHandler is kept here for documentation purposes.
// The last exception seems more like what we want.
const size_t kLastExceptionHandler = 0;
g_vector_exception_handler = AddVectoredExceptionHandler(kLastExceptionHandler, vectorExceptionHandling);
#endif
}
} // end namespace g3

View File

@@ -1,117 +0,0 @@
/** ==========================================================================
* 2013 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================*/
#include "g3log/filesink.hpp"
#include <cassert>
#include <chrono>
#include "filesinkhelper.ipp"
namespace g3 {
using namespace internal;
FileSink::FileSink(const std::string& log_prefix, const std::string& log_directory, const std::string& logger_id, size_t write_to_log_every_x_message) :
_log_details_func(&LogMessage::DefaultLogDetailsToString),
_log_file_with_path(log_directory),
_log_prefix_backup(log_prefix),
_outptr(new std::ofstream),
_header("\t\tLOG format: [YYYY/MM/DD hh:mm:ss uuu* LEVEL FILE->FUNCTION:LINE] message\n\n\t\t(uuu*: microseconds fractions of the seconds value)\n\n"),
_firstEntry(true),
_write_counter(0),
_write_to_log_every_x_message(write_to_log_every_x_message) {
_log_prefix_backup = prefixSanityFix(log_prefix);
if (!isValidFilename(_log_prefix_backup)) {
std::cerr << "g3log: forced abort due to illegal log prefix [" << log_prefix << "]" << std::endl;
abort();
}
std::string file_name = createLogFileName(_log_prefix_backup, logger_id);
_log_file_with_path = pathSanityFix(_log_file_with_path, file_name);
_outptr = createLogFile(_log_file_with_path);
if (!_outptr) {
std::cerr << "Cannot write log file to location, attempting current directory" << std::endl;
_log_file_with_path = "./" + file_name;
_outptr = createLogFile(_log_file_with_path);
}
assert(_outptr && "cannot open log file at startup");
}
FileSink::~FileSink() {
std::string exit_msg = {"g3log g3FileSink shutdown at: "};
auto now = std::chrono::system_clock::now();
exit_msg.append(localtime_formatted(now, internal::time_formatted)).append("\n");
// write anything buffered up and then end with the exit msg
filestream() << _write_buffer << exit_msg << std::flush;
exit_msg.append("Log file at: [").append(_log_file_with_path).append("]\n");
std::cerr << exit_msg << std::flush;
}
// The actual log receiving function
void FileSink::fileWrite(LogMessageMover message) {
if (_firstEntry) {
addLogFileHeader();
_firstEntry = false;
}
auto data = message.get().toString(_log_details_func);
_write_buffer.append(data);
if (++_write_counter % _write_to_log_every_x_message == 0) {
filestream() << _write_buffer << std::flush;
_write_buffer.clear();
}
}
std::string FileSink::changeLogFile(const std::string& directory, const std::string& logger_id) {
auto now = std::chrono::system_clock::now();
auto now_formatted = g3::localtime_formatted(now, {internal::date_formatted + " " + internal::time_formatted});
std::string file_name = createLogFileName(_log_prefix_backup, logger_id);
std::string prospect_log = directory + file_name;
std::unique_ptr<std::ofstream> log_stream = createLogFile(prospect_log);
if (nullptr == log_stream) {
filestream() << "\n"
<< now_formatted << " Unable to change log file. Illegal filename or busy? Unsuccessful log name was: " << prospect_log;
return {}; // no success
}
addLogFileHeader();
std::ostringstream ss_change;
ss_change << "\n\tChanging log file from : " << _log_file_with_path;
ss_change << "\n\tto new location: " << prospect_log << "\n";
filestream() << now_formatted << ss_change.str();
ss_change.str("");
std::string old_log = _log_file_with_path;
_log_file_with_path = std::move(prospect_log);
_outptr = std::move(log_stream);
ss_change << "\n\tNew log file. The previous log file was at: ";
ss_change << old_log << "\n";
filestream() << now_formatted << ss_change.str();
return _log_file_with_path;
}
std::string FileSink::fileName() {
return _log_file_with_path;
}
void FileSink::overrideLogDetails(LogMessage::LogDetailsFunc func) {
_log_details_func = func;
}
void FileSink::overrideLogHeader(const std::string& change) {
_header = change;
}
void FileSink::addLogFileHeader() {
filestream() << header(_header);
}
} // namespace g3

View File

@@ -1,127 +0,0 @@
/** ==========================================================================
* 2013 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================*/
#pragma once
#include <memory>
#include <string>
#include <algorithm>
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
namespace g3 {
namespace internal {
static const std::string file_name_time_formatted = "%Y%m%d-%H%M%S";
// check for filename validity - filename should not be part of PATH
bool isValidFilename(const std::string &prefix_filename) {
std::string illegal_characters("/,|<>:#$%{}[]\'\"^!?+* ");
size_t pos = prefix_filename.find_first_of(illegal_characters, 0);
if (pos != std::string::npos) {
std::cerr << "Illegal character [" << prefix_filename.at(pos) << "] in logname prefix: " << "[" << prefix_filename << "]" << std::endl;
return false;
} else if (prefix_filename.empty()) {
std::cerr << "Empty filename prefix is not allowed" << std::endl;
return false;
}
return true;
}
std::string prefixSanityFix(std::string prefix) {
prefix.erase(std::remove_if(prefix.begin(), prefix.end(), ::isspace), prefix.end());
prefix.erase(std::remove(prefix.begin(), prefix.end(), '/'), prefix.end());
prefix.erase(std::remove(prefix.begin(), prefix.end(), '\\'), prefix.end());
prefix.erase(std::remove(prefix.begin(), prefix.end(), '.'), prefix.end());
prefix.erase(std::remove(prefix.begin(), prefix.end(), ':'), prefix.end());
if (!isValidFilename(prefix)) {
return
{
};
}
return prefix;
}
std::string pathSanityFix(std::string path, const std::string &file_name) {
// Unify the delimeters,. maybe sketchy solution but it seems to work
// on at least win7 + ubuntu. All bets are off for older windows
std::replace(path.begin(), path.end(), '\\', '/');
// clean up in case of multiples
auto contains_end = [&](std::string & in) -> bool {
size_t size = in.size();
if (!size) return false;
char end = in[size - 1];
return (end == '/' || end == ' ');
};
while (contains_end(path)) {
path.erase(path.size() - 1);
}
if (!path.empty()) {
path.insert(path.end(), '/');
}
path.insert(path.size(), file_name);
return path;
}
std::string header(const std::string& headerFormat) {
std::ostringstream ss_entry;
// Day Month Date Time Year: is written as "%a %b %d %H:%M:%S %Y" and formatted output as : Wed Sep 19 08:28:16 2012
auto now = std::chrono::system_clock::now();
ss_entry << "\t\tg3log created log at: " << g3::localtime_formatted(now, "%a %b %d %H:%M:%S %Y") << "\n";
ss_entry << headerFormat;
return ss_entry.str();
}
std::string createLogFileName(const std::string &verified_prefix, const std::string &logger_id) {
std::stringstream oss_name;
oss_name << verified_prefix << ".";
if( !logger_id.empty() ) {
oss_name << logger_id << ".";
}
auto now = std::chrono::system_clock::now();
oss_name << g3::localtime_formatted(now, file_name_time_formatted);
oss_name << ".log";
return oss_name.str();
}
bool openLogFile(const std::string &complete_file_with_path, std::ofstream &outstream) {
std::ios_base::openmode mode = std::ios_base::out; // for clarity: it's really overkill since it's an ofstream
mode |= std::ios_base::trunc;
outstream.open(complete_file_with_path, mode);
if (!outstream.is_open()) {
std::ostringstream ss_error;
ss_error << "FILE ERROR: could not open log file:[" << complete_file_with_path << "]";
ss_error << "\n\t\t std::ios_base state = " << outstream.rdstate();
std::cerr << ss_error.str().c_str() << std::endl;
outstream.close();
return false;
}
return true;
}
std::unique_ptr<std::ofstream> createLogFile(const std::string &file_with_full_path) {
std::unique_ptr<std::ofstream> out(new std::ofstream);
std::ofstream &stream(*(out.get()));
bool success_with_open_file = openLogFile(file_with_full_path, stream);
if (false == success_with_open_file) {
out.reset();
}
return out;
}
}
}

View File

@@ -1,22 +0,0 @@
/** ==========================================================================
* 2015 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================*/
#pragma once
// For convenience: If you don't want to do a recursive search and replace in your source code
// for replacing g2log.hpp for g3log/g3log.hpp then you can choose to add this header file to your
// code. It will get the necessary includes
//
//
// Btw: replacing g2log for g3log include is easy on Linux
// find . -name "*.cpp*" -print | xargs sed -i -e 's/\g2log\.hpp/\g3log\/g3log\.hpp/g'
#include <g3log/filesink.hpp>
#include <g3log/g3log.hpp>
#include <g3log/loglevels.hpp>
#include <g3log/logworker.hpp>

View File

@@ -1,242 +0,0 @@
/** ==========================================================================
* 2011 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================
*
* Filename:g3log.cpp Framework for Logging and Design By Contract
* Created: 2011 by Kjell Hedström
*
* PUBLIC DOMAIN and Not copyrighted since it was built on public-domain software and at least in "spirit" influenced
* from the following sources
* 1. kjellkod.cc ;)
* 2. Dr.Dobbs, Petru Marginean: http://drdobbs.com/article/printableArticle.jhtml?articleId=201804215&dept_url=/cpp/
* 3. Dr.Dobbs, Michael Schulze: http://drdobbs.com/article/printableArticle.jhtml?articleId=225700666&dept_url=/cpp/
* 4. Google 'glog': http://google-glog.googlecode.com/svn/trunk/doc/glog.html
* 5. Various Q&A at StackOverflow
* ********************************************* */
#include "g3log/g3log.hpp"
#include "g3log/crashhandler.hpp"
#include "g3log/loglevels.hpp"
#include "g3log/logmessage.hpp"
#include "g3log/logworker.hpp"
#include <atomic>
#include <cstdlib>
#include <iostream>
#include <memory>
#include <mutex>
#include <sstream>
#include <thread>
namespace {
std::once_flag g_initialize_flag;
g3::LogWorker* g_logger_instance = nullptr; // instantiated and OWNED somewhere else (main)
std::mutex g_logging_init_mutex;
std::unique_ptr<g3::LogMessage> g_first_uninitialized_msg = {nullptr};
std::once_flag g_set_first_uninitialized_flag;
std::once_flag g_save_first_uninitialized_flag;
const std::function<void(void)> g_pre_fatal_hook_that_does_nothing = [] { /*does nothing */ };
std::function<void(void)> g_fatal_pre_logging_hook;
std::atomic<size_t> g_fatal_hook_recursive_counter = {0};
} // namespace
namespace g3 {
// signalhandler and internal clock is only needed to install once
// for unit testing purposes the initializeLogging might be called
// several times...
// for all other practical use, it shouldn't!
void initializeLogging(LogWorker* bgworker) {
std::call_once(g_initialize_flag, [] {
installCrashHandler();
});
std::lock_guard<std::mutex> lock(g_logging_init_mutex);
if (internal::isLoggingInitialized() || nullptr == bgworker) {
std::ostringstream exitMsg;
exitMsg << __FILE__ "->" << __FUNCTION__ << ":" << __LINE__ << std::endl;
exitMsg << "\tFatal exit due to illegal initialization of g3::LogWorker\n";
exitMsg << "\t(due to multiple initializations? : " << std::boolalpha << internal::isLoggingInitialized();
exitMsg << ", due to nullptr == bgworker? : " << std::boolalpha << (nullptr == bgworker) << ")";
std::cerr << exitMsg.str() << std::endl;
std::exit(EXIT_FAILURE);
}
// Save the first uninitialized message, if any
std::call_once(g_save_first_uninitialized_flag, [&bgworker] {
if (g_first_uninitialized_msg) {
bgworker->save(LogMessagePtr{std::move(g_first_uninitialized_msg)});
}
});
g_logger_instance = bgworker;
// by default the pre fatal logging hook does nothing
// if it WOULD do something it would happen in
setFatalPreLoggingHook(g_pre_fatal_hook_that_does_nothing);
// recursive crash counter re-set to zero
g_fatal_hook_recursive_counter.store(0);
}
/**
* default does nothing, @ref ::g_pre_fatal_hook_that_does_nothing
* It will be called just before sending the fatal message, @ref pushFatalmessageToLogger
* It will be reset to do nothing in ::initializeLogging(...)
* so please call this function, if you ever need to, after initializeLogging(...)
*/
void setFatalPreLoggingHook(std::function<void(void)> pre_fatal_hook) {
static std::mutex m;
std::lock_guard<std::mutex> lock(m);
g_fatal_pre_logging_hook = pre_fatal_hook;
}
// By default this function pointer goes to \ref pushFatalMessageToLogger;
std::function<void(FatalMessagePtr)> g_fatal_to_g3logworker_function_ptr = internal::pushFatalMessageToLogger;
/** REPLACE fatalCallToLogger for fatalCallForUnitTest
* This function switches the function pointer so that only
* 'unitTest' mock-fatal calls are made.
* */
void setFatalExitHandler(std::function<void(FatalMessagePtr)> fatal_call) {
g_fatal_to_g3logworker_function_ptr = fatal_call;
}
namespace internal {
bool isLoggingInitialized() {
return g_logger_instance != nullptr;
}
/**
* Shutdown the logging by making the pointer to the background logger to nullptr. The object is not deleted
* that is the responsibility of its owner. *
*/
void shutDownLogging() {
std::lock_guard<std::mutex> lock(g_logging_init_mutex);
g_logger_instance = nullptr;
}
/** Same as the Shutdown above but called by the destructor of the LogWorker, thus ensuring that no further
* LOG(...) calls can happen to a non-existing LogWorker.
* @param active MUST BE the LogWorker initialized for logging. If it is not then this call is just ignored
* and the logging continues to be active.
* @return true if the correct worker was given,. and shutDownLogging was called
*/
bool shutDownLoggingForActiveOnly(LogWorker* active) {
if (isLoggingInitialized() && nullptr != active && (active != g_logger_instance)) {
LOG(WARNING) << "\n\t\tAttempted to shut down logging, but the ID of the Logger is not the one that is active."
<< "\n\t\tHaving multiple instances of the g3::LogWorker is likely a BUG"
<< "\n\t\tEither way, this call to shutDownLogging was ignored"
<< "\n\t\tTry g3::internal::shutDownLogging() instead";
return false;
}
shutDownLogging();
return true;
}
/** explicitly copy of all input. This is makes it possibly to use g3log across dynamically loaded libraries
* i.e. (dlopen + dlsym) */
void saveMessage(const char* entry, const char* file, int line, const char* function, const LEVELS& level,
const char* boolean_expression, int fatal_signal, const char* stack_trace) {
LEVELS msgLevel{level};
LogMessagePtr message{std::make_unique<LogMessage>(file, line, function, msgLevel)};
message.get()->write().append(entry);
message.get()->setExpression(boolean_expression);
if (internal::wasFatal(level)) {
saveFatalMessage(stack_trace, message, fatal_signal);
} else {
pushMessageToLogger(message);
}
}
void saveFatalMessage(const char* stack_trace, g3::LogMessagePtr& message, int& fatal_signal) {
auto fatalhook = g_fatal_pre_logging_hook;
// In case the fatal_pre logging actually will cause a crash in its turn
// let's not do recursive crashing!
setFatalPreLoggingHook(g_pre_fatal_hook_that_does_nothing);
++g_fatal_hook_recursive_counter; // thread safe counter
// "benign" race here. If two threads crashes, with recursive crashes
// then it's possible that the "other" fatal stack trace will be shown
// that's OK since it was anyhow the first crash detected
static const std::string first_stack_trace = stack_trace;
fatalhook();
message.get()->write().append(stack_trace);
if (g_fatal_hook_recursive_counter.load() > 1) {
message.get()->write().append(
"\n\n\nWARNING\n"
"A recursive crash detected. It is likely the hook set with 'setFatalPreLoggingHook(...)' is responsible\n\n")
.append("---First crash stacktrace: ")
.append(first_stack_trace)
.append("\n---End of first stacktrace\n");
}
FatalMessagePtr fatal_message{std::make_unique<FatalMessage>(*(message._move_only.get()), fatal_signal)};
// At destruction, flushes fatal message to g3LogWorker
// either we will stay here until the background worker has received the fatal
// message, flushed the crash message to the sinks and exits with the same fatal signal
//..... OR it's in unit-test mode then we throw a std::runtime_error (and never hit sleep)
fatalCall(fatal_message);
}
/**
* save the message to the logger. In case of called before the logger is instantiated
* the first message will be saved. Any following subsequent uninitialized log calls
* will be ignored.
*
* The first initialized log entry will also save the first uninitialized log message, if any
* @param log_entry to save to logger
*/
void pushMessageToLogger(LogMessagePtr incoming) { // todo rename to Push SavedMessage To Worker
// Uninitialized messages are ignored but does not CHECK/crash the logger
if (!internal::isLoggingInitialized()) {
std::call_once(g_set_first_uninitialized_flag, [&] {
g_first_uninitialized_msg = incoming.release();
std::string err = {"LOGGER NOT INITIALIZED:\n\t\t"};
err.append(g_first_uninitialized_msg->message());
std::string& str = g_first_uninitialized_msg->write();
str.clear();
str.append(err); // replace content
std::cerr << str << std::endl; });
return;
}
// logger is initialized
g_logger_instance->save(incoming);
}
/** Fatal call saved to logger. This will trigger SIGABRT or other fatal signal
* to exit the program. After saving the fatal message the calling thread
* will sleep forever (i.e. until the background thread catches up, saves the fatal
* message and kills the software with the fatal signal.
*/
void pushFatalMessageToLogger(FatalMessagePtr message) {
if (!isLoggingInitialized()) {
std::ostringstream error;
error << "FATAL CALL but logger is NOT initialized\n"
<< "CAUSE: " << message.get()->reason()
<< "\nMessage: \n"
<< message.get()->toString() << std::flush;
std::cerr << error.str() << std::flush;
internal::exitWithDefaultSignalHandler(message.get()->_level, message.get()->_signal_id);
}
g_logger_instance->fatal(message);
while (shouldBlockForFatalHandling()) {
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
/** The default, initial, handling to send a 'fatal' event to g3logworker
* the caller will stay here, eternally, until the software is aborted
* ... in the case of unit testing it is the given "Mock" fatalCall that will
* define the behaviour.
*/
void fatalCall(FatalMessagePtr message) {
g_fatal_to_g3logworker_function_ptr(FatalMessagePtr{std::move(message)});
}
} // namespace internal
} // namespace g3

View File

@@ -1,67 +0,0 @@
/** ==========================================================================
* 2010 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================
*
* Example of a Active Object, using C++11 std::thread mechanisms to make it
* safe for thread communication.
*
* This was originally published at http://sites.google.com/site/kjellhedstrom2/active-object-with-cpp0x
* and inspired from Herb Sutter's C++11 Active Object
* http://herbsutter.com/2010/07/12/effective-concurrency-prefer-using-active-objects-instead-of-naked-threads
*
* Last update 2013-12-19 by Kjell Hedstrom,
* e-mail: hedstrom at kjellkod dot cc
* linkedin: http://linkedin.com/se/kjellkod */
#pragma once
#include <functional>
#include <memory>
#include <thread>
#include "g3log/shared_queue.hpp"
namespace kjellkod {
typedef std::function<void()> Callback;
class Active {
private:
Active() :
done_(false) {} // Construction ONLY through factory createActive();
Active(const Active&) = delete;
Active& operator=(const Active&) = delete;
void run() {
while (!done_) {
Callback func;
mq_.wait_and_pop(func);
func();
}
}
shared_queue<Callback> mq_;
std::thread thd_;
bool done_;
public:
virtual ~Active() {
send([this]() noexcept { done_ = true; });
thd_.join();
}
void send(Callback msg_) {
mq_.push(msg_);
}
/// Factory: safe construction of object before thread start
static std::unique_ptr<Active> createActive() {
std::unique_ptr<Active> aPtr(new Active());
aPtr->thd_ = std::thread(&Active::run, aPtr.get());
return aPtr;
}
};
} // namespace kjellkod

View File

@@ -1,47 +0,0 @@
/** ==========================================================================
* 2015 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================*/
#pragma once
#include <atomic>
namespace g3 {
/// As suggested in: http://stackoverflow.com/questions/13193484/how-to-declare-a-vector-of-atomic-in-c
struct atomicbool {
private:
std::atomic<bool> value_;
public:
atomicbool() :
value_{false} {}
atomicbool(bool value) :
value_{value} {}
atomicbool(const std::atomic<bool>& value) :
value_{value.load(std::memory_order_acquire)} {}
atomicbool(const atomicbool& other) :
value_{other.value_.load(std::memory_order_acquire)} {}
atomicbool& operator=(const atomicbool& other) {
value_.store(other.value_.load(std::memory_order_acquire), std::memory_order_release);
return *this;
}
atomicbool& operator=(const bool other) {
value_.store(other, std::memory_order_release);
return *this;
}
bool operator==(const atomicbool& rhs) const {
return (value_.load(std::memory_order_acquire) == rhs.value_.load(std::memory_order_acquire));
}
bool value() { return value_.load(std::memory_order_acquire); }
std::atomic<bool>& get() { return value_; }
};
} // namespace g3
// explicit whitespace/EOF for VS15

View File

@@ -1,81 +0,0 @@
#pragma once
/** ==========================================================================
* 2011 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================*/
#include <cstdio>
#include <map>
#include <string>
#include "g3log/loglevels.hpp"
// kjell. Separera på crashhandler.hpp och crashhanlder_internal.hpp
// implementationsfilen kan vara den samma
namespace g3 {
// PUBLIC API:
/** Install signal handler that catches FATAL C-runtime or OS signals
See the wikipedia site for details http://en.wikipedia.org/wiki/SIGFPE
See the this site for example usage: http://www.tutorialspoint.com/cplusplus/cpp_signal_handling
SIGABRT ABORT (ANSI), abnormal termination
SIGFPE Floating point exception (ANSI)
SIGILL ILlegal instruction (ANSI)
SIGSEGV Segmentation violation i.e. illegal memory reference
SIGTERM TERMINATION (ANSI) */
void installCrashHandler();
#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
typedef unsigned long SignalType;
/// SIGFPE, SIGILL, and SIGSEGV handling must be installed per thread
/// on Windows. This is automatically done if you do at least one LOG(...) call
/// you can also use this function call, per thread so make sure these three
/// fatal signals are covered in your thread (even if you don't do a LOG(...) call
void installSignalHandlerForThread();
#else
typedef int SignalType;
std::string signalToStr(int signal_number);
// restore to whatever signal handler was used before signal handler installation
void restoreSignalHandler(int signal_number);
/// Overrides the existing signal handling for custom signals
/// For example: usage of zcmq relies on its own signal handler for SIGTERM
/// so users of g3log with zcmq should then use the @ref overrideSetupSignals
/// , likely with the original set of signals but with SIGTERM removed
///
/// call example:
/// g3::overrideSetupSignals({ {SIGABRT, "SIGABRT"}, {SIGFPE, "SIGFPE"},{SIGILL, "SIGILL"},
// {SIGSEGV, "SIGSEGV"},});
void overrideSetupSignals(const std::map<int, std::string> overrideSignals);
#endif
namespace internal {
/// Resets the fatal signal/exception handling back to default
/// which might be needed in case it was previously overridden
/// The default signals are: SIGABRT, SIGFPE, SIGILL, SIGSEGV, SIGTERM
void restoreFatalHandlingToDefault();
/** return whether or any fatal handling is still ongoing
* this is used by g3log::fatalCallToLogger
* only in the case of Windows exceptions (not fatal signals)
* are we interested in changing this from false to true to
* help any other exceptions handler work with 'EXCEPTION_CONTINUE_SEARCH'*/
bool shouldBlockForFatalHandling();
/** \return signal_name Ref: signum.hpp and \ref installSignalHandler
* or for Windows exception name */
std::string exitReasonName(const LEVELS& level, g3::SignalType signal_number);
/** return calling thread's stackdump*/
std::string stackdump(const char* dump = nullptr);
/** Re-"throw" a fatal signal, previously caught. This will exit the application
* This is an internal only function. Do not use it elsewhere. It is triggered
* from g3log, g3LogWorker after flushing messages to file */
void exitWithDefaultSignalHandler(const LEVELS& level, g3::SignalType signal_number);
size_t writeErrorMessage(const char* message);
} // namespace internal
} // namespace g3

View File

@@ -1,46 +0,0 @@
/** ==========================================================================
* 2013 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================*/
#pragma once
#include <memory>
#include <string>
#include "g3log/logmessage.hpp"
namespace g3 {
class FileSink {
public:
FileSink(const std::string& log_prefix, const std::string& log_directory, const std::string& logger_id = "g3log", size_t write_to_log_every_x_message = 100);
virtual ~FileSink();
void fileWrite(LogMessageMover message);
std::string changeLogFile(const std::string& directory, const std::string& logger_id);
std::string fileName();
void overrideLogDetails(LogMessage::LogDetailsFunc func);
void overrideLogHeader(const std::string& change);
private:
LogMessage::LogDetailsFunc _log_details_func;
std::string _log_file_with_path;
std::string _log_prefix_backup; // needed in case of future log file changes of directory
std::unique_ptr<std::ofstream> _outptr;
std::string _header;
bool _firstEntry;
std::string _write_buffer;
size_t _write_counter;
size_t _write_to_log_every_x_message;
void addLogFileHeader();
std::ofstream& filestream() {
return *(_outptr.get());
}
FileSink& operator=(const FileSink&) = delete;
FileSink(const FileSink& other) = delete;
};
} // namespace g3

View File

@@ -1,60 +0,0 @@
#pragma once
/** ==========================================================================
* 2012 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================
* Filename:g3future.hpp
* Helper functionality to put packaged_tasks in standard container. This
* is especially helpful for background thread processing a la async but through
* an actor pattern (active object), thread pool or similar.
* Created: 2012 by Kjell Hedström
*
* COMMUNITY THANKS:
* The code below is in large thanks to exemplifying code snippets from StackOverflow
* question/answer: http://stackoverflow.com/questions/6230893/developing-c-concurrency-library-with-futures-or-similar-paradigm
* and a discussion between Lars Gullik Bjønnes and Jonathan Wakely's at: http://gcc.gnu.org/ml/gcc-help/2011-11/msg00052.html
*
* Both are highly recommended reads if you are interested in c++ concurrency library
* - Kjell, 2012
*
* PUBLIC DOMAIN and NOT under copywrite protection.
* ********************************************* */
#include <future>
#include "g3log/active.hpp"
#include "g3log/moveoncopy.hpp"
#include "g3log/stlpatch_future.hpp"
namespace g3 {
// Generic helper function to avoid repeating the steps for managing
// asynchronous task job (by active object) that returns a future results
// could of course be made even more generic if done more in the way of
// std::async, ref: http://en.cppreference.com/w/cpp/thread/async
//
// Example usage:
// std::unique_ptr<Active> bgWorker{Active::createActive()};
// ...
// auto msg_call=[=](){return ("Hello from the Background");};
// auto future_msg = g3::spawn_task(msg_lambda, bgWorker.get());
template <typename Func, class BgWorker>
std::future<std::invoke_result_t<Func>> spawn_task(Func func, BgWorker* worker) {
typedef std::invoke_result_t<Func> result_type;
typedef std::packaged_task<result_type()> task_type;
if (nullptr == worker) {
auto p = std::make_shared<std::promise<result_type>>();
std::future<result_type> future_result = p->get_future();
p->set_exception(std::make_exception_ptr(std::runtime_error("nullptr instantiated worker")));
return future_result;
}
task_type task(std::move(func));
std::future<result_type> result = task.get_future();
worker->send(MoveOnCopy<task_type>(std::move(task)));
return result;
}
} // end namespace g3

View File

@@ -1,226 +0,0 @@
/** ==========================================================================
* 2011 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================
*
* Filename:g3log.hpp Framework for Logging and Design By Contract
* Created: 2011 by Kjell Hedström
*
* PUBLIC DOMAIN and Not copywrited since it was built on public-domain software and influenced
* at least in "spirit" from the following sources
* 1. kjellkod.cc ;)
* 2. Dr.Dobbs, Petru Marginean: http://drdobbs.com/article/printableArticle.jhtml?articleId=201804215&dept_url=/caddpp/
* 3. Dr.Dobbs, Michael Schulze: http://drdobbs.com/article/printableArticle.jhtml?articleId=225700666&dept_url=/cpp/
* 4. Google 'glog': http://google-glog.googlecode.com/svn/trunk/doc/glog.html
* 5. Various Q&A at StackOverflow
* ********************************************* */
#pragma once
#include "g3log/logcapture.hpp"
#include "g3log/loglevels.hpp"
#include "g3log/logmessage.hpp"
#include <functional>
#include <string>
#if defined(_MSC_VER) && (defined(WINDOWS_FUNCSIG)) // Microsoft
#define G3LOG_PRETTY_FUNCTION __FUNCSIG__
#elif defined(__GNUC__) && defined(PRETTY_FUNCTION) // GCC compatible
#define G3LOG_PRETTY_FUNCTION __PRETTY_FUNCTION__
#else
#define G3LOG_PRETTY_FUNCTION __FUNCTION__
#endif
// thread_local doesn't exist before VS2013
// it exists on VS2015
#if !(defined(thread_local)) && defined(_MSC_VER) && _MSC_VER < 1900
#define thread_local __declspec(thread)
#endif
/** namespace for LOG() and CHECK() frameworks
* History lesson: Why the names 'g3' and 'g3log'?:
* The framework was made in my own free time as PUBLIC DOMAIN but the
* first commercial project to use it used 'g3' as an internal denominator for
* the current project. g3 as in 'generation 2'. I decided to keep the g3 and g3log names
* to give credit to the people in that project (you know who you are :) and I guess also
* for 'sentimental' reasons. That a big influence was Google's glog is just a happy
* coincidence or subconscious choice. Either way g3log became the name for this logger.
*
* --- Thanks for a great 2011 and good luck with 'g3' --- KjellKod
*/
namespace g3 {
class LogWorker;
struct LogMessage;
struct FatalMessage;
/** Should be called at very first startup of the software with \ref g3LogWorker
* pointer. Ownership of the \ref g3LogWorker is the responsibility of the caller */
void initializeLogging(LogWorker* logger);
/** setFatalPreLoggingHook() provides an optional extra step before the fatalExitHandler is called
*
* Set a function-hook before a fatal message will be sent to the logger
* i.e. this is a great place to put a break point, either in your debugger
* or programmatically to catch LOG(FATAL), CHECK(...) or an OS fatal event (exception or signal)
* This will be reset to default (does nothing) at initializeLogging(...);
*
* Example usage:
* Windows: g3::setFatalPreLoggingHook([]{__debugbreak();}); // remember #include <intrin.h>
* WARNING: '__debugbreak()' when not running in Debug in your Visual Studio IDE will likely
* trigger a recursive crash if used here. It should only be used when debugging
* in your Visual Studio IDE. Recursive crashes are handled but are unnecessary.
*
* Linux: g3::setFatalPreLoggingHook([]{ raise(SIGTRAP); });
*/
void setFatalPreLoggingHook(std::function<void(void)> pre_fatal_hook);
/** If the @ref setFatalPreLoggingHook is not enough and full fatal exit handling is needed then
* use "setFatalExithandler". Please see g3log.cpp and crashhandler_windows.cpp or crashhandler_unix for
* example of restoring signal and exception handlers, flushing the log and shutting down.
*/
void setFatalExitHandler(std::function<void(FatalMessagePtr)> fatal_call);
#ifdef G3_DYNAMIC_MAX_MESSAGE_SIZE
// only_change_at_initialization namespace is for changes to be done only during initialization. More specifically
// items here would be called prior to calling other parts of g3log
namespace only_change_at_initialization {
// Sets the MaxMessageSize to be used when capturing log messages. Currently this value is set to 2KB. Messages
// Longer than this are bound to 2KB with the string "[...truncated...]" at the end. This function allows
// this limit to be changed.
void setMaxMessageSize(size_t max_size);
} // namespace only_change_at_initialization
#endif /* G3_DYNAMIC_MAX_MESSAGE_SIZE */
// internal namespace is for completely internal or semi-hidden from the g3 namespace due to that it is unlikely
// that you will use these
namespace internal {
/// @returns true if logger is initialized
bool isLoggingInitialized();
// Save the created LogMessage to any existing sinks
void saveMessage(const char* message, const char* file, int line, const char* function, const LEVELS& level,
const char* boolean_expression, int fatal_signal, const char* stack_trace);
void saveFatalMessage(const char* stack_trace, g3::LogMessagePtr& message, int& fatal_signal);
// forwards the message to all sinks
void pushMessageToLogger(LogMessagePtr log_entry);
// forwards a FATAL message to all sinks,. after which the g3logworker
// will trigger crashhandler / g3::internal::exitWithDefaultSignalHandler
//
// By default the "fatalCall" will forward a FatalMessageptr to this function
// this behavior can be changed if you set a different fatal handler through
// "setFatalExitHandler"
void pushFatalMessageToLogger(FatalMessagePtr message);
// Saves the created FatalMessage to any existing sinks and exits with
// the originating fatal signal,. or SIGABRT if it originated from a broken contract.
// By default forwards to: pushFatalMessageToLogger, see "setFatalExitHandler" to override
//
// If you override it then you probably want to call "pushFatalMessageToLogger" after your
// custom fatal handler is done. This will make sure that the fatal message the pushed
// to sinks as well as shutting down the process
void fatalCall(FatalMessagePtr message);
// Shuts down logging. No object cleanup but further LOG(...) calls will be ignored.
void shutDownLogging();
// Shutdown logging, but ONLY if the active logger corresponds to the one currently initialized
bool shutDownLoggingForActiveOnly(LogWorker* active);
} // namespace internal
} // namespace g3
// clang-format off
#define INTERNAL_LOG_MESSAGE(level) LogCapture(__FILE__, __LINE__, static_cast<const char*>(G3LOG_PRETTY_FUNCTION), level)
#define INTERNAL_CONTRACT_MESSAGE(boolean_expression) \
LogCapture(__FILE__, __LINE__, G3LOG_PRETTY_FUNCTION, g3::internal::CONTRACT, boolean_expression)
// LOG(level) is the API for the stream log
#define LOG(level) if (!g3::logLevel(level)) {} else INTERNAL_LOG_MESSAGE(level).stream()
// 'Conditional' stream log
#define LOG_IF(level, boolean_expression) \
if (!g3::logLevel(level) || false == (boolean_expression)) {} else INTERNAL_LOG_MESSAGE(level).stream()
// 'Design By Contract' stream API. Broken Contracts will exit the application by using fatal signal SIGABRT
// For unit testing, you can override the fatal handling using setFatalExitHandler(...). See tes_io.cpp for examples
#define CHECK(boolean_expression) \
if (true == (boolean_expression)) {} else INTERNAL_CONTRACT_MESSAGE(#boolean_expression).stream()
/** For details please see this
* REFERENCE: http://www.cppreference.com/wiki/io/c/printf_format
* \verbatim
*
There are different %-codes for different variable types, as well as options to
limit the length of the variables and whatnot.
Code Format
%[flags][width][.precision][length]specifier
SPECIFIERS
----------
%c character
%d signed integers
%i signed integers
%e scientific notation, with a lowercase “e”
%E scientific notation, with a uppercase “E”
%f floating point
%g use %e or %f, whichever is shorter
%G use %E or %f, whichever is shorter
%o octal
%s a string of characters
%u unsigned integer
%x unsigned hexadecimal, with lowercase letters
%X unsigned hexadecimal, with uppercase letters
%p a pointer
%n the argument shall be a pointer to an integer into which is placed the number of characters written so far
For flags, width, precision etc please see the above references.
EXAMPLES:
{
LOGF(INFO, "Characters: %c %c \n", 'a', 65);
LOGF(INFO, "Decimals: %d %ld\n", 1977, 650000L); // printing long
LOGF(INFO, "Preceding with blanks: %10d \n", 1977);
LOGF(INFO, "Preceding with zeros: %010d \n", 1977);
LOGF(INFO, "Some different radixes: %d %x %o %#x %#o \n", 100, 100, 100, 100, 100);
LOGF(INFO, "floats: %4.2f %+.0e %E \n", 3.1416, 3.1416, 3.1416);
LOGF(INFO, "Width trick: %*d \n", 5, 10);
LOGF(INFO, "%s \n", "A string");
return 0;
}
And here is possible output
: Characters: a A
: Decimals: 1977 650000
: Preceding with blanks: 1977
: Preceding with zeros: 0000001977
: Some different radixes: 100 64 144 0x64 0144
: floats: 3.14 +3e+000 3.141600E+000
: Width trick: 10
: A string \endverbatim */
#define LOGF(level, printf_like_message, ...) \
if (!g3::logLevel(level)) {} else INTERNAL_LOG_MESSAGE(level).capturef(printf_like_message, ##__VA_ARGS__)
// Conditional log printf syntax
#define LOGF_IF(level,boolean_expression, printf_like_message, ...) \
if (!g3::logLevel(level) || false == (boolean_expression)) {} else INTERNAL_LOG_MESSAGE(level).capturef(printf_like_message, ##__VA_ARGS__)
// Design By Contract, printf-like API syntax with variadic input parameters.
// Calls the signal handler if the contract failed with the default exit for a failed contract. This is typically SIGABRT
// See g3log, setFatalExitHandler(...) which can be overriden for unit tests (ref test_io.cpp)
#define CHECKF(boolean_expression, printf_like_message, ...) \
if (true == (boolean_expression)) {} else INTERNAL_CONTRACT_MESSAGE(#boolean_expression).capturef(printf_like_message, ##__VA_ARGS__)
// Backwards compatible. The same as CHECKF.
// Design By Contract, printf-like API syntax with variadic input parameters.
// Calls the signal handler if the contract failed. See g3log, setFatalExitHandler(...) which can be overriden for unit tests
// (ref test_io.cpp)
#define CHECK_F(boolean_expression, printf_like_message, ...) \
if (true == (boolean_expression)) {} else INTERNAL_CONTRACT_MESSAGE(#boolean_expression).capturef(printf_like_message, ##__VA_ARGS__)
// clang-format on

View File

@@ -1,75 +0,0 @@
/** ==========================================================================
* 2013 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================*/
#pragma once
#include "g3log/crashhandler.hpp"
#include "g3log/loglevels.hpp"
#include <csignal>
#include <cstdarg>
#include <sstream>
#include <string>
#ifdef _MSC_VER
#include <sal.h>
#endif
/**
* Simple struct for capturing log/fatal entries. At destruction the captured message is
* forwarded to background worker.
* As a safety precaution: No memory allocated here will be moved into the background
* worker in case of dynamic loaded library reasons
*/
struct LogCapture {
/// Called from crash handler when a fatal signal has occurred (SIGSEGV etc)
LogCapture(const LEVELS& level, g3::SignalType fatal_signal, const char* dump = nullptr);
/**
* @file, line, function are given in g3log.hpp from macros
* @level INFO/DEBUG/WARNING/FATAL
* @expression for CHECK calls
* @fatal_signal for failed CHECK:SIGABRT or fatal signal caught in the signal handler
*/
LogCapture(const char* file, const int line, const char* function, const LEVELS& level, const char* expression = "", g3::SignalType fatal_signal = SIGABRT, const char* dump = nullptr);
// At destruction the message will be forwarded to the g3log worker.
// In the case of dynamically (at runtime) loaded libraries, the important thing to know is that
// all strings are copied, so the original are not destroyed at the receiving end, only the copy
virtual ~LogCapture() noexcept(false);
#ifdef _MSC_VER
#if _MSC_VER >= 1400
#define G3LOG_FORMAT_STRING _Printf_format_string_
#else
#define G3LOG_FORMAT_STRING __format_string
#endif
void capturef(G3LOG_FORMAT_STRING const char* printf_like_message, ...);
#else
#define G3LOG_FORMAT_STRING
// Use "-Wall" to generate warnings in case of illegal printf format.
// Ref: http://www.unixwiz.net/techtips/gnu-c-attributes.html
[[gnu::format(printf, 2, 3)]] void capturef(G3LOG_FORMAT_STRING const char* printf_like_message, ...); // 2,3 ref: http://www.codemaestro.com/reviews/18
#endif
/// prettifying API for this completely open struct
std::ostringstream& stream() {
return _stream;
}
std::ostringstream _stream;
std::string _stack_trace;
const char* _file;
const int _line;
const char* _function;
const LEVELS& _level;
const char* _expression;
const g3::SignalType _fatal_signal;
};
//} // g3

View File

@@ -1,194 +0,0 @@
/** ==========================================================================
* 2012 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================*/
#pragma once
// Users of Juce or other libraries might have a define DEBUG which clashes with
// the DEBUG logging level for G3log. In that case they can instead use the define
// "CHANGE_G3LOG_DEBUG_TO_DBUG" and G3log's logging level DEBUG is changed to be DBUG
#if (defined(CHANGE_G3LOG_DEBUG_TO_DBUG))
#if (defined(DBUG))
#error "DBUG is already defined elsewhere which clashes with G3Log's log level DBUG"
#endif
#else
#if (defined(DEBUG))
#error "DEBUG is already defined elsewhere which clashes with G3Log's log level DEBUG"
#endif
#endif
#include <algorithm>
#include <atomic>
#include <g3log/atomicbool.hpp>
#include <map>
#include <string>
// Levels for logging, made so that it would be easy to change, remove, add levels -- KjellKod
struct LEVELS {
// force internal copy of the const char*. This is a simple safeguard for when g3log is used in a
// "dynamic, runtime loading of shared libraries"
LEVELS(const LEVELS& other) :
value(other.value),
text(other.text.c_str()) {}
LEVELS(int id, const std::string& idtext) :
value(id),
text(idtext) {}
bool operator==(const LEVELS& rhs) const {
return (value == rhs.value && text == rhs.text);
}
bool operator!=(const LEVELS& rhs) const {
return (value != rhs.value || text != rhs.text);
}
friend void swap(LEVELS& first, LEVELS& second) {
using std::swap;
swap(first.value, second.value);
swap(first.text, second.text);
}
LEVELS& operator=(LEVELS other) {
swap(*this, other);
return *this;
}
int value;
std::string text;
};
// If you want to add any extra logging level then please add to your own source file the logging level you need
// 1. If the cmake option G3_DYNAMIC_LOGGING is enabled then you must use g3::only_change_at_initialization::addLogLevel(...).
// to give g3log a record of your logging level and if it is an enabled or disbled logging level.
//
// 2. If the cmake dynamic logging option is turned OFF
// then giving g3log a record of your logging level with 'addLogLevel(...) is NOT needed since no "disbled/enabled"
// check will happen - all logging levels will be considered enabled.
// 3. See also the [g3log/API.markdown](https://github.com/KjellKod/g3log/blob/master/API.markdown) for for information.
//
// example: MyLoggingLevel.h
// #pragma once
// const LEVELS MYINFO {WARNING.value +1, "MyInfoLevel"};
// const LEVELS MYFATAL {FATAL.value +1, "MyFatalLevel"};
//
// ... somewhere else when G3_DYNAMIC_LOGGING is enabled
// addLogLevel(MYINFO, true);
// LOG(MYINFO) << "some text";
//
// ... another example, when G3_DYNAMIC_LOGGING is enabled
// 'addLogLevel' is NOT required
// LOG(MYFATAL) << "this will just work, and it will be counted as a FATAL event";
namespace g3 {
static const int kDebugValue = 100;
static const int kInfoValue = 300;
static const int kWarningValue = 500;
static const int kFatalValue = 1000;
static const int kInternalFatalValue = 2000;
} // namespace g3
const LEVELS G3LOG_DEBUG{g3::kDebugValue, "DEBUG"},
INFO{g3::kInfoValue, "INFO"},
WARNING{g3::kWarningValue, "WARNING"},
FATAL{g3::kFatalValue, "FATAL"};
namespace g3 {
// Logging level and atomic status collection struct
struct LoggingLevel {
atomicbool status;
LEVELS level;
// default operator needed for std::map compliance
LoggingLevel() :
status(false),
level(INFO){};
LoggingLevel(const LoggingLevel& lvl) :
status(lvl.status),
level(lvl.level) {}
LoggingLevel(const LEVELS& lvl) :
status(true),
level(lvl){};
LoggingLevel(const LEVELS& lvl, bool enabled) :
status(enabled),
level(lvl){};
~LoggingLevel() = default;
LoggingLevel& operator=(const LoggingLevel& other) {
status = other.status;
level = other.level;
return *this;
}
bool operator==(const LoggingLevel& rhs) const {
return (status == rhs.status && level == rhs.level);
}
};
} // namespace g3
namespace g3 {
namespace internal {
const LEVELS CONTRACT{g3::kInternalFatalValue, {"CONTRACT"}},
FATAL_SIGNAL{g3::kInternalFatalValue + 1, {"FATAL_SIGNAL"}},
FATAL_EXCEPTION{kInternalFatalValue + 2, {"FATAL_EXCEPTION"}};
/// helper function to tell the logger if a log message was fatal. If it is it will force
/// a shutdown after all log entries are saved to the sinks
bool wasFatal(const LEVELS& level);
} // namespace internal
#ifdef G3_DYNAMIC_LOGGING
// Only safe if done at initialization in a single-thread context
namespace only_change_at_initialization {
/// add a custom level - enabled or disabled
void addLogLevel(LEVELS level, bool enabled);
/// add a custom level - enabled
void addLogLevel(LEVELS level);
/// reset all default logging levels to enabled
/// remove any added logging levels so that the only ones left are
/// {DEBUG,INFO,WARNING,FATAL}
void reset();
} // namespace only_change_at_initialization
namespace log_levels {
/// Enable log level >= log_level.
/// log levels below will be disabled
/// log levels equal or higher will be enabled.
void setHighest(LEVELS level);
void set(LEVELS level, bool enabled);
void disable(LEVELS level);
void enable(LEVELS level);
/// WARNING: This will also disable FATAL events from being logged
void disableAll();
void enableAll();
/// print all levels with their disabled or enabled status
std::string to_string(std::map<int, g3::LoggingLevel> levelsToPrint);
/// print snapshot of system levels with their
/// disabled or enabled status
std::string to_string();
/// Snapshot view of the current logging levels' status
std::map<int, g3::LoggingLevel> getAll();
enum class status { Absent,
Enabled,
Disabled };
status getStatus(LEVELS level);
} // namespace log_levels
#endif
/// Enabled status for the given logging level
bool logLevel(const LEVELS& level);
} // namespace g3

View File

@@ -1,148 +0,0 @@
/** ==========================================================================
* 2012 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================*/
#pragma once
#include "g3log/crashhandler.hpp"
#include "g3log/loglevels.hpp"
#include "g3log/moveoncopy.hpp"
#include "g3log/time.hpp"
#include <memory>
#include <sstream>
#include <string>
#include <thread>
namespace g3 {
/** LogMessage contains all the data collected from the LOG(...) call.
* If the sink receives a std::string it will be the std::string toString()... function
* that will format the data into a string
*
* For sinks that receive a LogMessage they can either use the toString() function, or use
* the helper functions or even the public raw data to format the saved log message any
* desired way.
*/
struct LogMessage {
std::string file_path() const {
return _file_path;
}
std::string file() const {
return _file;
}
std::string line() const {
return std::to_string(_line);
}
std::string function() const {
return _function;
}
std::string level() const {
return _level.text;
}
/// use a different format string to get a different look on the time.
// default look is Y/M/D H:M:S
std::string timestamp(const std::string& time_format = {internal::date_formatted + " " + internal::time_formatted}) const;
std::string message() const {
return _message;
}
std::string& write() const {
return _message;
}
std::string expression() const {
return _expression;
}
bool wasFatal() const {
return internal::wasFatal(_level);
}
std::string threadID() const;
void setExpression(std::string expression) {
_expression = std::move(expression);
}
LogMessage& operator=(LogMessage other);
LogMessage(std::string file, const int line, std::string function, const LEVELS level);
explicit LogMessage(const std::string& fatalOsSignalCrashMessage);
LogMessage(const LogMessage& other);
LogMessage(LogMessage&& other);
virtual ~LogMessage() {}
// helper log printing functions used by "toString()"
static std::string splitFileName(const std::string& str);
static std::string fatalSignalToString(const LogMessage& msg);
// windows only: fatalExceptionToString
static std::string fatalExceptionToString(const LogMessage& msg);
static std::string fatalLogToString(const LogMessage& msg);
static std::string fatalCheckToString(const LogMessage& msg);
static std::string normalToString(const LogMessage& msg);
// the default formatting option
static std::string DefaultLogDetailsToString(const LogMessage& msg);
// this function can be used by the logging sink to add thread ID
// see this concept and it is easy to make your own custom formatting
static std::string FullLogDetailsToString(const LogMessage& msg);
using LogDetailsFunc = std::string (*)(const LogMessage&);
std::string toString(LogDetailsFunc formattingFunc = DefaultLogDetailsToString) const;
void overrideLogDetailsFunc(LogDetailsFunc func) const;
//
// Complete access to the raw data in case the helper functions above
// are not enough.
//
mutable LogDetailsFunc _logDetailsToStringFunc;
g3::high_resolution_time_point _timestamp;
std::thread::id _call_thread_id;
std::string _file;
std::string _file_path;
int _line;
std::string _function;
LEVELS _level;
std::string _expression; // only with content for CHECK(...) calls
mutable std::string _message;
friend void swap(LogMessage& first, LogMessage& second) {
using std::swap;
swap(first._timestamp, second._timestamp);
swap(first._call_thread_id, second._call_thread_id);
swap(first._file, second._file);
swap(first._line, second._line);
swap(first._function, second._function);
swap(first._level, second._level);
swap(first._expression, second._expression);
swap(first._message, second._message);
}
};
/** Trigger for flushing the message queue and exiting the application
* A thread that causes a FatalMessage will sleep forever until the
* application has exited (after message flush) */
struct FatalMessage : public LogMessage {
FatalMessage(const LogMessage& details, g3::SignalType signal_id);
FatalMessage(const FatalMessage&);
FatalMessage& operator=(const FatalMessage&) = delete;
virtual ~FatalMessage() {}
LogMessage copyToLogMessage() const;
std::string reason() const;
const SignalType _signal_id;
};
typedef MoveOnCopy<std::unique_ptr<FatalMessage>> FatalMessagePtr;
typedef MoveOnCopy<std::unique_ptr<LogMessage>> LogMessagePtr;
typedef MoveOnCopy<LogMessage> LogMessageMover;
} // namespace g3

View File

@@ -1,143 +0,0 @@
#pragma once
/** ==========================================================================
* 2011 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================
* Filename:g3logworker.h Framework for Logging and Design By Contract
* Created: 2011 by Kjell Hedström
*
* PUBLIC DOMAIN and Not copyrighted. First published at KjellKod.cc
* ********************************************* */
#include <memory>
#include "g3log/filesink.hpp"
#include "g3log/g3log.hpp"
#include "g3log/logmessage.hpp"
#include "g3log/sinkhandle.hpp"
#include "g3log/sinkwrapper.hpp"
#include <memory>
#include <string>
#include <vector>
namespace g3 {
class LogWorker;
struct LogWorkerImpl;
using FileSinkHandle = g3::SinkHandle<g3::FileSink>;
/// Background side of the LogWorker. Internal use only
struct LogWorkerImpl final {
typedef std::shared_ptr<g3::internal::SinkWrapper> SinkWrapperPtr;
std::vector<SinkWrapperPtr> _sinks;
std::unique_ptr<kjellkod::Active> _bg; // do not change declaration order. _bg must be destroyed before sinks
LogWorkerImpl();
~LogWorkerImpl() = default;
void bgSave(g3::LogMessagePtr msgPtr);
void bgFatal(FatalMessagePtr msgPtr);
LogWorkerImpl(const LogWorkerImpl&) = delete;
LogWorkerImpl& operator=(const LogWorkerImpl&) = delete;
};
/// Front end of the LogWorker. API that is useful is
/// addSink( sink, default_call ) which returns a handle to the sink. See below and README for usage example
/// save( msg ) : internal use
/// fatal ( fatal_msg ) : internal use
class LogWorker final {
LogWorker() = default;
void addWrappedSink(std::shared_ptr<g3::internal::SinkWrapper> wrapper);
LogWorkerImpl _impl;
LogWorker(const LogWorker&) = delete;
LogWorker& operator=(const LogWorker&) = delete;
public:
~LogWorker();
/// Creates the LogWorker with no sinks. See example below on @ref addSink for how to use it
/// if you want to use the default file logger then see below for @ref addDefaultLogger
static std::unique_ptr<LogWorker> createLogWorker();
/**
A convenience function to add the default g3::FileSink to the log worker
@param log_prefix that you want
@param log_directory where the log is to be stored.
@return a handle for API access to the sink. See the README for example usage
@verbatim
Example:
using namespace g3;
std::unique_ptr<LogWorker> logworker {LogWorker::createLogWorker()};
auto handle = addDefaultLogger("my_test_log", "/tmp");
initializeLogging(logworker.get()); // ref. g3log.hpp
std::future<std::string> log_file_name = sinkHandle->call(&FileSink::fileName);
std::cout << "The filename is: " << log_file_name.get() << std::endl;
// something like: /tmp/my_test_log.g3log.20150819-100300.log
*/
std::unique_ptr<FileSinkHandle> addDefaultLogger(const std::string& log_prefix, const std::string& log_directory, const std::string& default_id = "g3log");
/// Adds a sink and returns the handle for access to the sink
/// @param real_sink unique_ptr ownership is passed to the log worker
/// @param call the default call that should receive either a std::string or a LogMessageMover message
/// @return handle to the sink for API access. See usage example below at @ref addDefaultLogger
template <typename T, typename DefaultLogCall>
std::unique_ptr<g3::SinkHandle<T>> addSink(std::unique_ptr<T> real_sink, DefaultLogCall call) {
using namespace g3;
using namespace g3::internal;
auto sink = std::make_shared<Sink<T>>(std::move(real_sink), call);
addWrappedSink(sink);
return std::make_unique<SinkHandle<T>>(sink);
}
/// Removes a sink. This is a synchronous call.
/// You are guaranteed that the sink is removed by the time the call returns
/// @param sink_handle the ownership of the sink handle is given
template <typename T>
void removeSink(std::unique_ptr<SinkHandle<T>> sink_handle) {
if (sink_handle) {
// sink_handle->sink().use_count() is 1 at this point
// i.e. this would be safe as long as no other weak_ptr to shared_ptr conversion
// was made by the client: assert(sink_handle->sink().use_count() == 0);
auto weak_ptr_sink = sink_handle->sink();
{
auto bg_removesink_call = [this, weak_ptr_sink] {
auto shared_sink = weak_ptr_sink.lock();
if (shared_sink) {
_impl._sinks.erase(std::remove(_impl._sinks.begin(), _impl._sinks.end(), shared_sink), _impl._sinks.end());
}
};
auto token_done = g3::spawn_task(bg_removesink_call, _impl._bg.get());
token_done.wait();
}
// sink_handle->sink().use_count() is 1 at this point.
// i.e. this would be safe: assert(sink_handle->sink().use_count() == 0);
// as long as the client has not converted more instances from the weak_ptr
}
}
/// This will clear/remove all the sinks. If a sink shared_ptr was retrieved via the sink
/// handle then the sink will be removed internally but will live on in the client's instance
void removeAllSinks() {
auto bg_clear_sink_call = [this]() noexcept {
_impl._sinks.clear();
};
auto token_cleared = g3::spawn_task(bg_clear_sink_call, _impl._bg.get());
token_cleared.wait();
}
/// internal:
/// pushes in background thread (asynchronously) input messages to log file
void save(LogMessagePtr entry);
/// internal:
// pushes a fatal message on the queue, this is the last message to be processed
/// this way it's ensured that all existing entries were flushed before 'fatal'
/// Will abort the application!
void fatal(FatalMessagePtr fatal_message);
};
} // namespace g3

View File

@@ -1,51 +0,0 @@
/** ==========================================================================
* 2013 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================*/
#pragma once
namespace g3 {
// A straightforward technique to move around packaged_tasks.
// Instances of std::packaged_task are MoveConstructible and MoveAssignable, but
// not CopyConstructible or CopyAssignable. To put them in a std container they need
// to be wrapped and their internals "moved" when tried to be copied.
template <typename Moveable>
struct MoveOnCopy {
mutable Moveable _move_only;
explicit MoveOnCopy(Moveable&& m) :
_move_only(std::move(m)) {}
MoveOnCopy(MoveOnCopy const& t) :
_move_only(std::move(t._move_only)) {}
MoveOnCopy(MoveOnCopy&& t) :
_move_only(std::move(t._move_only)) {}
MoveOnCopy& operator=(MoveOnCopy const& other) {
_move_only = std::move(other._move_only);
return *this;
}
MoveOnCopy& operator=(MoveOnCopy&& other) {
_move_only = std::move(other._move_only);
return *this;
}
void operator()() {
_move_only();
}
Moveable& get() {
return _move_only;
}
Moveable release() {
return std::move(_move_only);
}
};
} // namespace g3

View File

@@ -1,78 +0,0 @@
/** ==========================================================================
* 2010 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================
*
* Example of a normal std::queue protected by a mutex for operations,
* making it safe for thread communication, using std::mutex from C++0x with
* the help from the std::thread library from JustSoftwareSolutions
* ref: http://www.stdthread.co.uk/doc/headers/mutex.html
*
* This example was totally inspired by Anthony Williams lock-based data structures in
* Ref: "C++ Concurrency In Action" http://www.manning.com/williams */
#pragma once
#include <condition_variable>
#include <exception>
#include <mutex>
#include <queue>
/** Multiple producer, multiple consumer thread safe queue
* Since 'return by reference' is used this queue won't throw */
template <typename T>
class shared_queue {
std::queue<T> queue_;
mutable std::mutex m_;
std::condition_variable data_cond_;
shared_queue& operator=(const shared_queue&) = delete;
shared_queue(const shared_queue& other) = delete;
public:
shared_queue() = default;
void push(T item) {
{
std::lock_guard<std::mutex> lock(m_);
queue_.push(std::move(item));
}
data_cond_.notify_one();
}
/// \return immediately, with true if successful retrieval
bool try_and_pop(T& popped_item) {
std::lock_guard<std::mutex> lock(m_);
if (queue_.empty()) {
return false;
}
popped_item = std::move(queue_.front());
queue_.pop();
return true;
}
/// Try to retrieve, if no items, wait till an item is available and try again
void wait_and_pop(T& popped_item) {
std::unique_lock<std::mutex> lock(m_);
while (queue_.empty()) {
data_cond_.wait(lock);
// This 'while' loop is equal to
// data_cond_.wait(lock, [](bool result){return !queue_.empty();});
}
popped_item = std::move(queue_.front());
queue_.pop();
}
bool empty() const {
std::lock_guard<std::mutex> lock(m_);
return queue_.empty();
}
unsigned size() const {
std::lock_guard<std::mutex> lock(m_);
return queue_.size();
}
};

View File

@@ -1,76 +0,0 @@
/** ==========================================================================
* 2013 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================*/
#pragma once
#include "g3log/active.hpp"
#include "g3log/future.hpp"
#include "g3log/logmessage.hpp"
#include "g3log/sinkwrapper.hpp"
#include <functional>
#include <memory>
#include <type_traits>
namespace g3 {
namespace internal {
typedef std::function<void(LogMessageMover)> AsyncMessageCall;
/// The asynchronous Sink has an active object, incoming requests for actions
// will be processed in the background by the specific object the Sink represents.
//
// The Sink will wrap either
// a Sink with Message object receiving call
// or a Sink with a LogEntry (string) receiving call
//
// The Sink can also be used through the SinkHandler to call Sink specific function calls
// Ref: send(Message) deals with incoming log entries (converted if necessary to string)
// Ref: send(Call call, Args... args) deals with calls
// to the real sink's API
template <class T>
struct Sink : public SinkWrapper {
std::unique_ptr<T> _real_sink;
std::unique_ptr<kjellkod::Active> _bg;
AsyncMessageCall _default_log_call;
template <typename DefaultLogCall>
Sink(std::unique_ptr<T> sink, DefaultLogCall call) :
SinkWrapper(),
_real_sink{std::move(sink)},
_bg(kjellkod::Active::createActive()),
_default_log_call(std::bind(call, _real_sink.get(), std::placeholders::_1)) {
}
Sink(std::unique_ptr<T> sink, void (T::*Call)(std::string)) :
SinkWrapper(),
_real_sink{std::move(sink)},
_bg(kjellkod::Active::createActive()) {
std::function<void(std::string)> adapter = std::bind(Call, _real_sink.get(), std::placeholders::_1);
_default_log_call = [=](LogMessageMover m) {
adapter(m.get().toString());
};
}
virtual ~Sink() {
_bg.reset(); // TODO: to remove
}
void send(LogMessageMover msg) override {
_bg->send([this, msg] {
_default_log_call(msg);
});
}
template <typename Call, typename... Args>
auto async(Call call, Args&&... args) -> std::future<std::invoke_result_t<decltype(call), T, Args...>> {
return g3::spawn_task(std::bind(call, _real_sink.get(), std::forward<Args>(args)...), _bg.get());
}
};
} // namespace internal
} // namespace g3

View File

@@ -1,59 +0,0 @@
/** ==========================================================================
* 2013 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================*/
#pragma once
#include "g3log/sink.hpp"
#include <memory>
#include <type_traits>
namespace g3 {
// The Sinkhandle is the client's access point to the specific sink instance.
// Only through the Sinkhandle can, and should, the real sink's specific API
// be called.
//
// The real sink will be owned by g3log. If the real sink is deleted
// calls to sink's API through the SinkHandle will return an exception embedded
// in the resulting future. Ref: SinkHandle::call
template <class T>
class SinkHandle {
std::weak_ptr<internal::Sink<T>> _sink;
public:
SinkHandle(std::shared_ptr<internal::Sink<T>> sink) :
_sink(sink) {}
~SinkHandle() = default;
// Asynchronous call to the real sink. If the real sink is already deleted
// the returned future will contain a bad_weak_ptr exception instead of the
// call result.
template <typename AsyncCall, typename... Args>
auto call(AsyncCall func, Args&&... args) -> std::future<std::invoke_result_t<decltype(func), T, Args...>> {
try {
std::shared_ptr<internal::Sink<T>> sink(_sink);
return sink->async(func, std::forward<Args>(args)...);
} catch (const std::bad_weak_ptr& e) {
typedef std::invoke_result_t<decltype(func), T, Args...> PromiseType;
std::promise<PromiseType> promise;
promise.set_exception(std::make_exception_ptr(e));
return std::move(promise.get_future());
}
}
/// Get weak_ptr access to the sink(). Make sure to check that the returned pointer is valid,
/// auto p = sink(); auto ptr = p.lock(); if (ptr) { .... }
/// ref: https://en.cppreference.com/w/cpp/memory/weak_ptr/lock
std::weak_ptr<internal::Sink<T>> sink() {
return _sink.lock();
}
};
} // namespace g3

View File

@@ -1,21 +0,0 @@
/** ==========================================================================
* 2013 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================*/
#pragma once
#include "g3log/logmessage.hpp"
namespace g3 {
namespace internal {
struct SinkWrapper {
virtual ~SinkWrapper() {}
virtual void send(LogMessageMover msg) = 0;
};
} // namespace internal
} // namespace g3

View File

@@ -1,41 +0,0 @@
/** ==========================================================================
* 2014 by KjellKod.cc AND Robert Engeln.
* The stacktrace code was given as a public domain dedication by Robert Engeln
* It was originally published at: http://code-freeze.blogspot.com/2012/01/generating-stack-traces-from-c.html
* It was (here) modified for g3log purposes.
*
* This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================*/
#pragma once
#if !(defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
#error "stacktrace_win.cpp used but not on a windows system"
#endif
#include "g3log/crashhandler.hpp"
#include <windows.h>
#include <string>
namespace stacktrace {
/// return the text description of a Windows exception code
std::string exceptionIdToText(g3::SignalType id);
/// return whether or not the exception is a known exception, i.e.
/// an exception that we should treat as a fatal event
bool isKnownException(g3::SignalType id);
/// helper function: retrieve stackdump from no excisting exception pointer
std::string stackdump();
/// helper function: retrieve stackdump, starting from an exception pointer
std::string stackdump(EXCEPTION_POINTERS* info);
/// main stackdump function. retrieve stackdump, from the given context
std::string stackdump(CONTEXT* context);
} // namespace stacktrace

View File

@@ -1,78 +0,0 @@
/** ==========================================================================
* 2013 This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
*
*
* 2013/12/28 Bugfix for Visual Studio 2013 which does not handle well
* std::packaged_task<void()>. Thanks to Michael Rasmussen (lap777)
* Ref: workarounds at http://connect.microsoft.com/VisualStudio/feedback/details/791185/std-packaged-task-t-where-t-is-void-or-a-reference-class-are-not-movable
* ============================================================================*/
#pragma once
#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) && !defined(__MINGW32__) && (_MSC_VER <= 1800)
namespace std {
template <class... _ArgTypes>
class packaged_task<void(_ArgTypes...)> {
promise<void> _my_promise;
function<void(_ArgTypes...)> _my_func;
public:
packaged_task() {
}
template <class _Fty2>
explicit packaged_task(_Fty2&& _Fnarg) :
_my_func(_Fnarg) {
}
packaged_task(packaged_task&& _Other) :
_my_promise(move(_Other._my_promise)),
_my_func(move(_Other._my_func)) {
}
packaged_task& operator=(packaged_task&& _Other) {
_my_promise = move(_Other._my_promise);
_my_func = move(_Other._my_func);
return (*this);
}
packaged_task(const packaged_task&) = delete;
packaged_task& operator=(const packaged_task&) = delete;
~packaged_task() {
}
void swap(packaged_task& _Other) {
swap(_my_promise, _Other._my_promise);
swap(_my_func, _Other._my_func);
}
explicit operator bool() const {
return _my_func != false;
}
bool valid() const {
return _my_func != false;
}
future<void> get_future() {
return _my_promise.get_future();
}
void operator()(_ArgTypes... _Args) {
_my_func(forward<_ArgTypes>(_Args)...);
_my_promise.set_value();
}
void reset() {
_my_promise.swap(promise<void>());
_my_func.swap(function<void(_ArgTypes...)>());
}
};
}; // namespace std
#endif // defined(WIN32) ...

View File

@@ -1,78 +0,0 @@
#pragma once
/** ==========================================================================
* 2012 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================
* Filename:g3time.h cross-platform, thread-safe replacement for C++11 non-thread-safe
* localtime (and similar)
* Created: 2012 by Kjell Hedström
*
* PUBLIC DOMAIN and Not under copywrite protection. First published for g3log at KjellKod.cc
* ********************************************* */
#include <chrono>
#include <ctime>
#include <string>
// FYI:
// namespace g3::internal ONLY in g3time.cpp
// std::string put_time(const struct tm* tmb, const char* c_time_format)
namespace g3 {
typedef std::chrono::time_point<std::chrono::system_clock> system_time_point;
typedef std::chrono::time_point<std::chrono::high_resolution_clock> high_resolution_time_point;
typedef std::chrono::milliseconds milliseconds;
typedef std::chrono::microseconds microseconds;
namespace internal {
enum class Fractional { Millisecond,
Microsecond,
Nanosecond,
NanosecondDefault };
Fractional getFractional(const std::string& format_buffer, size_t pos);
std::string to_string(const g3::system_time_point& ts, Fractional fractional);
std::string localtime_formatted_fractions(const g3::system_time_point& ts, std::string format_buffer);
static const std::string date_formatted = "%Y/%m/%d";
// %f: fractions of seconds (%f is nanoseconds)
// %f3: milliseconds, 3 digits: 001
// %6: microseconds: 6 digits: 000001 --- default for the time_format
// %f9, %f: nanoseconds, 9 digits: 000000001
static const std::string time_formatted = "%H:%M:%S %f6";
} // namespace internal
// This mimics the original "std::put_time(const std::tm* tmb, const charT* fmt)"
// This is needed since latest version (at time of writing) of gcc4.7 does not implement this library function yet.
// return value is SIMPLIFIED to only return a std::string
std::string put_time(const struct tm* tmb, const char* c_time_format);
/** return time representing POD struct (ref ctime + wchar) that is normally
* retrieved with std::localtime. g3::localtime is threadsafe which std::localtime is not.
* g3::localtime is probably used together with @ref g3::systemtime_now */
tm localtime(std::time_t time);
/** format string must conform to std::put_time's demands.
* WARNING: At time of writing there is only so-so compiler support for
* std::put_time. A possible fix if your c++11 library is not updated is to
* modify this to use std::strftime instead */
std::string localtime_formatted(const system_time_point& ts, const std::string& time_format);
inline system_time_point to_system_time(const high_resolution_time_point& ts) {
// On some (windows) systems, the system_clock does not provide the highest possible time
// resolution. Thus g3log uses high_resolution_clock for message time stamps. However,
// unlike system_clock, high_resolution_clock cannot be converted to a time and date as
// it usually measures reflects the time since power-up.
// Thus, hrs_now and sys_now are recorded once when the program starts to be able to convert
// timestamps to dime and date using to_system_time(). The precision of the absolute time is
// of course that of system_clock() with some error added due to the non-simultaneous initialization
// of the two static variables but relative times within one log will be as precise as
// high_resolution_clock.
using namespace std::chrono;
static const auto hrs_now = high_resolution_clock::now();
static const auto sys_now = system_clock::now();
return time_point_cast<system_clock::duration>(sys_now + (ts - hrs_now));
}
} // namespace g3

View File

@@ -1,113 +0,0 @@
/** ==========================================================================
* 2013 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================*/
#include "g3log/logcapture.hpp"
#include "g3log/crashhandler.hpp"
#include "g3log/g3log.hpp"
#ifdef G3_DYNAMIC_MAX_MESSAGE_SIZE
#include <vector>
#endif /* G3_DYNAMIC_MAX_MESSAGE_SIZE */
// For Windows we need force a thread_local install per thread of three
// signals that must have a signal handler installed per thread-basis
// It is really a royal pain. Seriously Microsoft? Seriously?
#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
#define SIGNAL_HANDLER_VERIFY() g3::installSignalHandlerForThread()
#else
// Does nothing --- enforces that semicolon must be written
#define SIGNAL_HANDLER_VERIFY() \
do { \
} while (0)
#endif
#ifdef G3_DYNAMIC_MAX_MESSAGE_SIZE
// MaxMessageSize is message limit used with vsnprintf/vsnprintf_s
static int MaxMessageSize = 2048;
void g3::only_change_at_initialization::setMaxMessageSize(size_t max_size) {
MaxMessageSize = max_size;
}
#endif /* G3_DYNAMIC_MAX_MESSAGE_SIZE */
/** logCapture is a simple struct for capturing log/fatal entries. At destruction the
* captured message is forwarded to background worker.
* As a safety precaution: No memory allocated here will be moved into the background
* worker in case of dynamic loaded library reasons instead the arguments are copied
* inside of g3log.cpp::saveMessage*/
LogCapture::~LogCapture() noexcept(false) {
using namespace g3::internal;
SIGNAL_HANDLER_VERIFY();
saveMessage(_stream.str().c_str(), _file, _line, _function, _level, _expression, _fatal_signal, _stack_trace.c_str());
}
/// Called from crash handler when a fatal signal has occurred (SIGSEGV etc)
LogCapture::LogCapture(const LEVELS& level, g3::SignalType fatal_signal, const char* dump) :
LogCapture("", 0, "", level, "", fatal_signal, dump) {
}
/**
* @file, line, function are given in g3log.hpp from macros
* @level INFO/DEBUG/WARNING/FATAL
* @expression for CHECK calls
* @fatal_signal for failed CHECK:SIGABRT or fatal signal caught in the signal handler
*/
LogCapture::LogCapture(const char* file, const int line, const char* function, const LEVELS& level,
const char* expression, g3::SignalType fatal_signal, const char* dump) :
_file(file),
_line(line),
_function(function),
_level(level),
_expression(expression),
_fatal_signal(fatal_signal) {
if (g3::internal::wasFatal(level)) {
_stack_trace = std::string{"\n*******\tSTACKDUMP *******\n"};
_stack_trace.append(g3::internal::stackdump(dump));
}
}
/**
* capturef, used for "printf" like API in CHECKF, LOGF, LOGF_IF
* See also for the attribute formatting ref: http://www.codemaestro.com/reviews/18
*/
void LogCapture::capturef(const char* printf_like_message, ...) {
static const std::string kTruncatedWarningText = "[...truncated...]";
#ifdef G3_DYNAMIC_MAX_MESSAGE_SIZE
std::vector<char> finished_message_backing(MaxMessageSize);
char* finished_message = finished_message_backing.data();
auto finished_message_len = MaxMessageSize;
#else
static const int kMaxMessageSize = 2048;
char finished_message[kMaxMessageSize];
#if ((defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) && !defined(__GNUC__))
auto finished_message_len = _countof(finished_message);
#else
int finished_message_len = sizeof(finished_message);
#endif
#endif /* G3_DYNAMIC_MAX_MESSAGE_SIZE*/
va_list arglist;
va_start(arglist, printf_like_message);
#if ((defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) && !defined(__GNUC__))
const int nbrcharacters = vsnprintf_s(finished_message, finished_message_len, _TRUNCATE, printf_like_message, arglist);
#else
const int nbrcharacters = vsnprintf(finished_message, finished_message_len, printf_like_message, arglist);
#endif
va_end(arglist);
if (nbrcharacters < 0) {
stream() << "\n\tERROR LOG MSG NOTIFICATION: Failure to successfully parse the message";
stream() << '"' << printf_like_message << '"' << std::endl;
} else if (nbrcharacters > finished_message_len) {
stream() << finished_message << kTruncatedWarningText;
} else {
stream() << finished_message;
}
}

View File

@@ -1,128 +0,0 @@
/** ==========================================================================
* 2012 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================*/
#include "g3log/loglevels.hpp"
#include <cassert>
#include <iostream>
namespace g3 {
namespace internal {
bool wasFatal(const LEVELS& level) {
return level.value >= FATAL.value;
}
#ifdef G3_DYNAMIC_LOGGING
const std::map<int, LoggingLevel> g_log_level_defaults = {
{G3LOG_DEBUG.value, {G3LOG_DEBUG}},
{INFO.value, {INFO}},
{WARNING.value, {WARNING}},
{FATAL.value, {FATAL}}};
std::map<int, g3::LoggingLevel> g_log_levels = g_log_level_defaults;
#endif
} // namespace internal
#ifdef G3_DYNAMIC_LOGGING
namespace only_change_at_initialization {
void addLogLevel(LEVELS lvl, bool enabled) {
int value = lvl.value;
internal::g_log_levels[value] = {lvl, enabled};
}
void addLogLevel(LEVELS level) {
addLogLevel(level, true);
}
void reset() {
g3::internal::g_log_levels = g3::internal::g_log_level_defaults;
}
} // namespace only_change_at_initialization
namespace log_levels {
void setHighest(LEVELS enabledFrom) {
auto it = internal::g_log_levels.find(enabledFrom.value);
if (it != internal::g_log_levels.end()) {
for (auto& v : internal::g_log_levels) {
if (v.first < enabledFrom.value) {
disable(v.second.level);
} else {
enable(v.second.level);
}
}
}
}
void set(LEVELS level, bool enabled) {
auto it = internal::g_log_levels.find(level.value);
if (it != internal::g_log_levels.end()) {
internal::g_log_levels[level.value] = {level, enabled};
}
}
void disable(LEVELS level) {
set(level, false);
}
void enable(LEVELS level) {
set(level, true);
}
void disableAll() {
for (auto& v : internal::g_log_levels) {
v.second.status = false;
}
}
void enableAll() {
for (auto& v : internal::g_log_levels) {
v.second.status = true;
}
}
std::string to_string(std::map<int, g3::LoggingLevel> levelsToPrint) {
std::string levels;
for (auto& v : levelsToPrint) {
levels += "name: " + v.second.level.text + " level: " + std::to_string(v.first) + " status: " + std::to_string(v.second.status.value()) + "\n";
}
return levels;
}
std::string to_string() {
return to_string(internal::g_log_levels);
}
std::map<int, g3::LoggingLevel> getAll() {
return internal::g_log_levels;
}
// status : {Absent, Enabled, Disabled};
status getStatus(LEVELS level) {
const auto it = internal::g_log_levels.find(level.value);
if (internal::g_log_levels.end() == it) {
return status::Absent;
}
return (it->second.status.get().load() ? status::Enabled : status::Disabled);
}
} // namespace log_levels
#endif
bool logLevel(const LEVELS& log_level) {
#ifdef G3_DYNAMIC_LOGGING
int level = log_level.value;
bool status = internal::g_log_levels[level].status.value();
return status;
#else
return true;
#endif
}
} // namespace g3

View File

@@ -1,193 +0,0 @@
/** ==========================================================================
* 2012 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================*/
#include "g3log/logmessage.hpp"
#include <mutex>
#include "g3log/crashhandler.hpp"
#include "g3log/time.hpp"
namespace g3 {
std::string LogMessage::splitFileName(const std::string& str) {
size_t found;
found = str.find_last_of("(/\\");
return str.substr(found + 1);
}
// helper for fatal signal
std::string LogMessage::fatalSignalToString(const LogMessage& msg) {
std::string out; // clear any previous text and formatting
out.append(msg.timestamp() + "\n\n***** FATAL SIGNAL RECEIVED ******* \n" + msg.message() + '\n');
return out;
}
// helper for fatal exception (windows only)
std::string LogMessage::fatalExceptionToString(const LogMessage& msg) {
std::string out; // clear any previous text and formatting
out.append(msg.timestamp() + "\n\n***** FATAL EXCEPTION RECEIVED ******* \n" + msg.message() + '\n');
return out;
}
// helper for fatal LOG
std::string LogMessage::fatalLogToString(const LogMessage& msg) {
auto out = msg._logDetailsToStringFunc(msg);
static const std::string fatalExitReason = {"EXIT trigger caused by LOG(FATAL) entry: "};
out.append("\n\t*******\t " + fatalExitReason + "\n\t" + '"' + msg.message() + '"');
return out;
}
// helper for fatal CHECK
std::string LogMessage::fatalCheckToString(const LogMessage& msg) {
auto out = msg._logDetailsToStringFunc(msg);
static const std::string contractExitReason = {"EXIT trigger caused by broken Contract:"};
out.append("\n\t*******\t " + contractExitReason + " CHECK(" + msg.expression() + ")\n\t" + '"' + msg.message() + '"');
return out;
}
// helper for setting the normal log details in an entry
std::string LogMessage::DefaultLogDetailsToString(const LogMessage& msg) {
std::string out;
out.append(msg.timestamp() + "\t" + msg.level() + " [" + msg.file() + "->" + msg.function() + ":" + msg.line() + "]\t");
return out;
}
std::string LogMessage::FullLogDetailsToString(const LogMessage& msg) {
std::string out;
out.append(msg.timestamp() + "\t" + msg.level() + " [" + msg.threadID() + " " + msg.file() + "->" + msg.function() + ":" + msg.line() + "]\t");
return out;
}
// helper for normal
std::string LogMessage::normalToString(const LogMessage& msg) {
auto out = msg._logDetailsToStringFunc(msg);
out.append(msg.message() + '\n');
return out;
}
// end static functions section
void LogMessage::overrideLogDetailsFunc(LogDetailsFunc func) const {
_logDetailsToStringFunc = func;
}
// Format the log message according to it's type
std::string LogMessage::toString(LogDetailsFunc formattingFunc) const {
overrideLogDetailsFunc(formattingFunc);
if (false == wasFatal()) {
return LogMessage::normalToString(*this);
}
const auto level_value = _level.value;
if (internal::FATAL_SIGNAL.value == _level.value) {
return LogMessage::fatalSignalToString(*this);
}
if (internal::FATAL_EXCEPTION.value == _level.value) {
return LogMessage::fatalExceptionToString(*this);
}
if (FATAL.value == _level.value) {
return LogMessage::fatalLogToString(*this);
}
if (internal::CONTRACT.value == level_value) {
return LogMessage::fatalCheckToString(*this);
}
// What? Did we hit a custom made level?
auto out = _logDetailsToStringFunc(*this);
static const std::string errorUnknown = {"UNKNOWN or Custom made Log Message Type"};
out.append("\t*******" + errorUnknown + "\n\t" + message() + '\n');
return out;
}
std::string LogMessage::timestamp(const std::string& time_look) const {
return g3::localtime_formatted(to_system_time(_timestamp), time_look);
}
// By copy, not by reference. See this explanation for details:
// http://stackoverflow.com/questions/3279543/what-is-the-copy-and-swap-idiom
LogMessage& LogMessage::operator=(LogMessage other) {
swap(*this, other);
return *this;
}
LogMessage::LogMessage(std::string file, const int line,
std::string function, const LEVELS level) :
_logDetailsToStringFunc(LogMessage::DefaultLogDetailsToString),
_timestamp(std::chrono::high_resolution_clock::now()),
_call_thread_id(std::this_thread::get_id())
#if defined(G3_LOG_FULL_FILENAME)
,
_file(file)
#else
,
_file(LogMessage::splitFileName(file))
#endif
,
_file_path(file),
_line(line),
_function(std::move(function)),
_level(level) {
}
LogMessage::LogMessage(const std::string& fatalOsSignalCrashMessage) :
LogMessage({""}, 0, {""}, internal::FATAL_SIGNAL) {
_message.append(fatalOsSignalCrashMessage);
}
LogMessage::LogMessage(const LogMessage& other) :
_logDetailsToStringFunc(other._logDetailsToStringFunc),
_timestamp(other._timestamp),
_call_thread_id(other._call_thread_id),
_file(other._file),
_file_path(other._file_path),
_line(other._line),
_function(other._function),
_level(other._level),
_expression(other._expression),
_message(other._message) {
}
LogMessage::LogMessage(LogMessage&& other) :
_logDetailsToStringFunc(other._logDetailsToStringFunc),
_timestamp(other._timestamp),
_call_thread_id(other._call_thread_id),
_file(std::move(other._file)),
_file_path(std::move(other._file_path)),
_line(other._line),
_function(std::move(other._function)),
_level(other._level),
_expression(std::move(other._expression)),
_message(std::move(other._message)) {
}
std::string LogMessage::threadID() const {
std::ostringstream oss;
oss << _call_thread_id;
return oss.str();
}
FatalMessage::FatalMessage(const LogMessage& details, g3::SignalType signal_id) :
LogMessage(details),
_signal_id(signal_id) {}
FatalMessage::FatalMessage(const FatalMessage& other) :
LogMessage(other),
_signal_id(other._signal_id) {}
LogMessage FatalMessage::copyToLogMessage() const {
return LogMessage(*this);
}
std::string FatalMessage::reason() const {
return internal::exitReasonName(_level, _signal_id);
}
} // namespace g3

View File

@@ -1,125 +0,0 @@
/** ==========================================================================
* 2011 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================*/
#include "g3log/logworker.hpp"
#include "g3log/active.hpp"
#include "g3log/crashhandler.hpp"
#include "g3log/future.hpp"
#include "g3log/g3log.hpp"
#include "g3log/logmessage.hpp"
#include <iostream>
namespace g3 {
LogWorkerImpl::LogWorkerImpl() :
_bg(kjellkod::Active::createActive()) {}
void LogWorkerImpl::bgSave(g3::LogMessagePtr msgPtr) {
std::unique_ptr<LogMessage> uniqueMsg(std::move(msgPtr.get()));
for (auto& sink : _sinks) {
LogMessage msg(*(uniqueMsg));
sink->send(LogMessageMover(std::move(msg)));
}
if (_sinks.empty()) {
std::string err_msg{"g3logworker has no sinks. Message: ["};
err_msg.append(uniqueMsg.get()->toString()).append("]\n");
std::cerr << err_msg;
}
}
void LogWorkerImpl::bgFatal(FatalMessagePtr msgPtr) {
// this will be the last message. Only the active logworker can receive a FATAL call so it's
// safe to shutdown logging now
g3::internal::shutDownLogging();
std::string reason = msgPtr.get()->reason();
const auto level = msgPtr.get()->_level;
const auto fatal_id = msgPtr.get()->_signal_id;
std::unique_ptr<LogMessage> uniqueMsg(std::move(msgPtr.get()));
uniqueMsg->write().append("\nExiting after fatal event (").append(uniqueMsg->level());
// Change output in case of a fatal signal (or windows exception)
std::string exiting = {"Fatal type: "};
uniqueMsg->write().append("). ").append(exiting).append(" ").append(reason).append("\nLog content flushed successfully to sink\n\n");
std::cerr << uniqueMsg->toString() << std::flush;
for (auto& sink : _sinks) {
LogMessage msg(*(uniqueMsg));
sink->send(LogMessageMover(std::move(msg)));
}
// This clear is absolutely necessary
// All sinks are forced to receive the fatal message above before we continue
_sinks.clear(); // flush all queues
internal::exitWithDefaultSignalHandler(level, fatal_id);
// should never reach this point
perror("g3log exited after receiving FATAL trigger. Flush message status: ");
}
LogWorker::~LogWorker() {
g3::internal::shutDownLoggingForActiveOnly(this);
// The sinks WILL automatically be cleared at exit of this destructor
// The waiting inside removeAllSinks ensures that all messages until this point are
// taken care of before any internals/LogWorkerImpl of LogWorker starts to be destroyed.
// i.e. this avoids a race with another thread slipping through the "shutdownLogging" and
// calling ::save or ::fatal through LOG/CHECK with lambda messages and "partly
// deconstructed LogWorkerImpl"
//
// Any messages put into the queue will be OK due to:
// *) If it is before the wait below then they will be executed
// *) If it is AFTER the wait below then they will be ignored and NEVER executed
removeAllSinks();
// The background worker WILL be automatically cleared at the exit of the destructor
// However, the explicitly clearing of the background worker (below) makes sure that there can
// be no thread that manages to add another sink after the call to clear the sinks above.
// i.e. this manages the extremely unlikely case of another thread calling
// addWrappedSink after the sink clear above. Normally adding of sinks should be done in main.cpp
// and be closely coupled with the existence of the LogWorker. Sharing this adding of sinks to
// other threads that do not know the state of LogWorker is considered a bug but it is dealt with
// nonetheless below.
//
// If sinks would already have been added after the sink clear above then this reset will deal with it
// without risking lambda execution with a partially deconstructed LogWorkerImpl
// Calling g3::spawn_task on a nullptr Active object will not crash but return
// a future containing an appropriate exception.
_impl._bg.reset(nullptr);
}
void LogWorker::save(LogMessagePtr msg) {
_impl._bg->send([this, msg] { _impl.bgSave(msg); });
}
void LogWorker::fatal(FatalMessagePtr fatal_message) {
_impl._bg->send([this, fatal_message] { _impl.bgFatal(fatal_message); });
}
void LogWorker::addWrappedSink(std::shared_ptr<g3::internal::SinkWrapper> sink) {
auto bg_addsink_call = [this, sink] {
_impl._sinks.push_back(sink);
};
auto token_done = g3::spawn_task(bg_addsink_call, _impl._bg.get());
token_done.wait();
}
std::unique_ptr<LogWorker> LogWorker::createLogWorker() {
return std::unique_ptr<LogWorker>(new LogWorker);
}
std::unique_ptr<FileSinkHandle> LogWorker::addDefaultLogger(const std::string& log_prefix, const std::string& log_directory, const std::string& default_id) {
return addSink(std::make_unique<g3::FileSink>(log_prefix, log_directory, default_id), &FileSink::fileWrite);
}
} // namespace g3

View File

@@ -1,196 +0,0 @@
/** ==========================================================================
* Original code made by Robert Engeln. Given as a PUBLIC DOMAIN dedication for
* the benefit of g3log. It was originally published at:
* http://code-freeze.blogspot.com/2012/01/generating-stack-traces-from-c.html
* 2014-2015: adapted for g3log by Kjell Hedstrom (KjellKod).
*
* This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================*/
#include "g3log/stacktrace_windows.hpp"
#include <dbghelp.h>
#include <windows.h>
#include <cassert>
#include <g3log/g3log.hpp>
#include <map>
#include <memory>
#include <mutex>
#include <vector>
#pragma comment(lib, "dbghelp.lib")
#if !(defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
#error "stacktrace_win.cpp used but not on a windows system"
#endif
#define g3_MAP_PAIR_STRINGIFY(x) \
{ x, #x }
namespace {
thread_local size_t g_thread_local_recursive_crash_check = 0;
const std::map<g3::SignalType, std::string> kExceptionsAsText = {
g3_MAP_PAIR_STRINGIFY(EXCEPTION_ACCESS_VIOLATION), g3_MAP_PAIR_STRINGIFY(EXCEPTION_ARRAY_BOUNDS_EXCEEDED), g3_MAP_PAIR_STRINGIFY(EXCEPTION_DATATYPE_MISALIGNMENT), g3_MAP_PAIR_STRINGIFY(EXCEPTION_FLT_DENORMAL_OPERAND), g3_MAP_PAIR_STRINGIFY(EXCEPTION_FLT_DIVIDE_BY_ZERO), g3_MAP_PAIR_STRINGIFY(EXCEPTION_FLT_INEXACT_RESULT), g3_MAP_PAIR_STRINGIFY(EXCEPTION_FLT_INEXACT_RESULT), g3_MAP_PAIR_STRINGIFY(EXCEPTION_FLT_INVALID_OPERATION), g3_MAP_PAIR_STRINGIFY(EXCEPTION_FLT_OVERFLOW), g3_MAP_PAIR_STRINGIFY(EXCEPTION_FLT_STACK_CHECK), g3_MAP_PAIR_STRINGIFY(EXCEPTION_FLT_UNDERFLOW), g3_MAP_PAIR_STRINGIFY(EXCEPTION_ILLEGAL_INSTRUCTION), g3_MAP_PAIR_STRINGIFY(EXCEPTION_IN_PAGE_ERROR), g3_MAP_PAIR_STRINGIFY(EXCEPTION_INT_DIVIDE_BY_ZERO), g3_MAP_PAIR_STRINGIFY(EXCEPTION_INT_OVERFLOW), g3_MAP_PAIR_STRINGIFY(EXCEPTION_INVALID_DISPOSITION), g3_MAP_PAIR_STRINGIFY(EXCEPTION_NONCONTINUABLE_EXCEPTION), g3_MAP_PAIR_STRINGIFY(EXCEPTION_PRIV_INSTRUCTION), g3_MAP_PAIR_STRINGIFY(EXCEPTION_STACK_OVERFLOW), g3_MAP_PAIR_STRINGIFY(EXCEPTION_BREAKPOINT), g3_MAP_PAIR_STRINGIFY(EXCEPTION_SINGLE_STEP)
};
// Using the given context, fill in all the stack frames.
// Which then later can be interpreted to human readable text
void captureStackTrace(CONTEXT* context, std::vector<uint64_t>& frame_pointers) {
DWORD machine_type = 0;
STACKFRAME64 frame = {}; // force zeroing
frame.AddrPC.Mode = AddrModeFlat;
frame.AddrFrame.Mode = AddrModeFlat;
frame.AddrStack.Mode = AddrModeFlat;
#if defined(_M_ARM64)
frame.AddrPC.Offset = context->Pc;
frame.AddrFrame.Offset = context->Fp;
frame.AddrStack.Offset = context->Sp;
machine_type = IMAGE_FILE_MACHINE_ARM64;
#elif defined(_M_ARM)
frame.AddrPC.Offset = context->Pc;
frame.AddrFrame.Offset = context->R11;
frame.AddrStack.Offset = context->Sp;
machine_type = IMAGE_FILE_MACHINE_ARM;
#elif defined(_M_X64)
frame.AddrPC.Offset = context->Rip;
frame.AddrFrame.Offset = context->Rbp;
frame.AddrStack.Offset = context->Rsp;
machine_type = IMAGE_FILE_MACHINE_AMD64;
#else
frame.AddrPC.Offset = context->Eip;
frame.AddrPC.Offset = context->Ebp;
frame.AddrPC.Offset = context->Esp;
machine_type = IMAGE_FILE_MACHINE_I386;
#endif
for (size_t index = 0; index < frame_pointers.size(); ++index) {
if (StackWalk64(machine_type,
GetCurrentProcess(),
GetCurrentThread(),
&frame,
context,
NULL,
SymFunctionTableAccess64,
SymGetModuleBase64,
NULL)) {
frame_pointers[index] = frame.AddrPC.Offset;
} else {
break;
}
}
}
// extract readable text from a given stack frame. All thanks to
// using SymFromAddr and SymGetLineFromAddr64 with the stack pointer
std::string getSymbolInformation(const size_t index, const std::vector<uint64_t>& frame_pointers) {
auto addr = frame_pointers[index];
std::string frame_dump = "stack dump [" + std::to_string(index) + "]\t";
DWORD64 displacement64;
DWORD displacement;
alignas(SYMBOL_INFO) char symbol_buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME];
SYMBOL_INFO* symbol = reinterpret_cast<SYMBOL_INFO*>(symbol_buffer);
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
symbol->MaxNameLen = MAX_SYM_NAME;
IMAGEHLP_LINE64 line;
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
std::string lineInformation;
std::string callInformation;
if (SymFromAddr(GetCurrentProcess(), addr, &displacement64, symbol)) {
callInformation.append(" ").append(std::string(symbol->Name, symbol->NameLen));
if (SymGetLineFromAddr64(GetCurrentProcess(), addr, &displacement, &line)) {
lineInformation.append("\t").append(line.FileName).append(" L: ");
lineInformation.append(std::to_string(line.LineNumber));
}
}
frame_dump.append(lineInformation).append(callInformation);
return frame_dump;
}
// Retrieves all the symbols for the stack frames, fills them within a text representation and returns it
std::string convertFramesToText(std::vector<uint64_t>& frame_pointers) {
std::string dump; // slightly more efficient than ostringstream
const size_t kSize = frame_pointers.size();
for (size_t index = 0; index < kSize && frame_pointers[index]; ++index) {
dump += getSymbolInformation(index, frame_pointers);
dump += "\n";
}
return dump;
}
} // namespace
namespace stacktrace {
const std::string kUnknown = {"UNKNOWN EXCEPTION"};
/// return the text description of a Windows exception code
/// From MSDN GetExceptionCode http://msdn.microsoft.com/en-us/library/windows/desktop/ms679356(v=vs.85).aspx
std::string exceptionIdToText(g3::SignalType id) {
const auto iter = kExceptionsAsText.find(id);
if (iter == kExceptionsAsText.end()) {
std::string unknown = {kUnknown + ":" + std::to_string(id)};
return unknown;
}
return iter->second;
}
/// Yes a double lookup: first for isKnownException and then exceptionIdToText
/// for vectored exceptions we only deal with known exceptions so this tiny
/// overhead we can live with
bool isKnownException(g3::SignalType id) {
return (kExceptionsAsText.end() != kExceptionsAsText.find(id));
}
/// helper function: retrieve stackdump from no excisting exception pointer
std::string stackdump() {
CONTEXT current_context;
memset(&current_context, 0, sizeof(CONTEXT));
RtlCaptureContext(&current_context);
return stackdump(&current_context);
}
/// helper function: retrieve stackdump, starting from an exception pointer
std::string stackdump(EXCEPTION_POINTERS* info) {
auto context = info->ContextRecord;
return stackdump(context);
}
/// main stackdump function. retrieve stackdump, from the given context
std::string stackdump(CONTEXT* context) {
if (g_thread_local_recursive_crash_check >= 2) { // In Debug scenarios we allow one extra pass
std::string recursive_crash = {"\n\n\n***** Recursive crash detected"};
recursive_crash.append(", cannot continue stackdump traversal. *****\n\n\n");
return recursive_crash;
}
++g_thread_local_recursive_crash_check;
static std::mutex m;
std::lock_guard<std::mutex> lock(m);
{
const BOOL kLoadSymModules = TRUE;
const auto initialized = SymInitialize(GetCurrentProcess(), nullptr, kLoadSymModules);
if (TRUE != initialized) {
return {"Error: Cannot call SymInitialize(...) for retrieving symbols in stack"};
}
std::shared_ptr<void> RaiiSymCleaner(nullptr, [&](void*) {
SymCleanup(GetCurrentProcess());
}); // Raii sym cleanup
constexpr size_t kmax_frame_dump_size = 64;
std::vector<uint64_t> frame_pointers(kmax_frame_dump_size);
// C++11: size set and values are zeroed
assert(frame_pointers.size() == kmax_frame_dump_size);
captureStackTrace(context, frame_pointers);
return convertFramesToText(frame_pointers);
}
}
} // namespace stacktrace

View File

@@ -1,151 +0,0 @@
/** ==========================================================================
* 2012 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================*/
#include "g3log/time.hpp"
#include <cassert>
#include <chrono>
#include <cmath>
#include <cstring>
#include <iomanip>
#include <sstream>
#include <string>
#ifdef __MACH__
#include <sys/time.h>
#endif
namespace g3 {
namespace internal {
const std::string kFractionalIdentier = "%f";
const size_t kFractionalIdentierSize = 2;
Fractional getFractional(const std::string& format_buffer, size_t pos) {
char ch = (format_buffer.size() > pos + kFractionalIdentierSize ? format_buffer.at(pos + kFractionalIdentierSize) : '\0');
Fractional type = Fractional::NanosecondDefault;
switch (ch) {
case '3':
type = Fractional::Millisecond;
break;
case '6':
type = Fractional::Microsecond;
break;
case '9':
type = Fractional::Nanosecond;
break;
default:
type = Fractional::NanosecondDefault;
break;
}
return type;
}
// Returns the fractional as a string with padded zeroes
// 1 ms --> 001
// 1 us --> 000001
// 1 ns --> 000000001
std::string to_string(const g3::system_time_point& ts, Fractional fractional) {
auto duration = ts.time_since_epoch();
auto sec_duration = std::chrono::duration_cast<std::chrono::seconds>(duration);
duration -= sec_duration;
auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(duration).count();
auto zeroes = 9; // default ns
auto digitsToCut = 1; // default ns, divide by 1 makes no change
switch (fractional) {
case Fractional::Millisecond: {
zeroes = 3;
digitsToCut = 1000000;
break;
}
case Fractional::Microsecond: {
zeroes = 6;
digitsToCut = 1000;
break;
}
case Fractional::Nanosecond:
case Fractional::NanosecondDefault:
default:
zeroes = 9;
digitsToCut = 1;
}
ns /= digitsToCut;
auto value = std::string(std::to_string(ns));
return std::string(zeroes - value.size(), '0') + value;
}
std::string localtime_formatted_fractions(const g3::system_time_point& ts, std::string format_buffer) {
// iterating through every "%f" instance in the format string
auto identifierExtraSize = 0;
for (size_t pos = 0;
(pos = format_buffer.find(g3::internal::kFractionalIdentier, pos)) != std::string::npos;
pos += g3::internal::kFractionalIdentierSize + identifierExtraSize) {
// figuring out whether this is nano, micro or milli identifier
auto type = g3::internal::getFractional(format_buffer, pos);
auto value = g3::internal::to_string(ts, type);
auto padding = 0;
if (type != g3::internal::Fractional::NanosecondDefault) {
padding = 1;
}
// replacing "%f[3|6|9]" with sec fractional part value
format_buffer.replace(pos, g3::internal::kFractionalIdentier.size() + padding, value);
}
return format_buffer;
}
} // namespace internal
} // namespace g3
namespace g3 {
// This mimics the original "std::put_time(const std::tm* tmb, const charT* fmt)"
// This is needed since latest version (at time of writing) of gcc4.7 does not implement this library function yet.
// return value is SIMPLIFIED to only return a std::string
std::string put_time(const struct tm* tmb, const char* c_time_format) {
#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) && !defined(__MINGW32__)
std::ostringstream oss;
oss.fill('0');
// BOGUS hack done for VS2012: C++11 non-conformant since it SHOULD take a "const struct tm* "
oss << std::put_time(const_cast<struct tm*>(tmb), c_time_format);
return oss.str();
#else // LINUX
const size_t size = 1024;
char buffer[size]; // IMPORTANT: check now and then for when gcc will implement std::put_time.
// ... also ... This is way more buffer space then we need
auto success = std::strftime(buffer, size, c_time_format, tmb);
// In DEBUG the assert will trigger a process exit. Once inside the if-statement
// the 'always true' expression will be displayed as reason for the exit
//
// In Production mode
// the assert will do nothing but the format string will instead be returned
if (0 == success) {
assert((0 != success) && "strftime fails with illegal formatting");
return c_time_format;
}
return buffer;
#endif
}
tm localtime(std::time_t ts) {
struct tm tm_snapshot;
#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
localtime_s(&tm_snapshot, &ts); // windsows
#else
localtime_r(&ts, &tm_snapshot); // POSIX
#endif
return tm_snapshot;
}
std::string localtime_formatted(const g3::system_time_point& ts, const std::string& time_format) {
auto format_buffer = internal::localtime_formatted_fractions(ts, time_format);
auto time_point = std::chrono::system_clock::to_time_t(ts);
std::tm t = localtime(time_point);
return g3::put_time(&t, format_buffer.c_str()); // format example: //"%Y/%m/%d %H:%M:%S");
}
} // namespace g3

View File

@@ -1,134 +0,0 @@
#pragma once
#include "common.hpp"
#include "g3log/g3log.hpp"
#include "g3log/logworker.hpp"
namespace peak
{
const LEVELS SUCCESS{200, {"SUCCESS"}};
const LEVELS ERR{800, "ERROR"};
class Logger;
inline Logger* logger{};
class Logger
{
public:
explicit Logger() :
worker(g3::LogWorker::createLogWorker())
{
AllocConsole();
consoleHandle = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTitleA("PeakMenu");
SetConsoleOutputCP(CP_UTF8);
RemoveMenu(GetSystemMenu(GetConsoleWindow(), FALSE), SC_CLOSE, MF_DISABLED);
SetConsoleCtrlHandler([](DWORD) -> BOOL
{
isRunning = false;
return TRUE;
}, TRUE);
consoleOut.open("CONOUT$", std::ios_base::out | std::ios_base::app);
size_t size = MAX_PATH;
char* buffer;
_dupenv_s(&buffer, &size, "APPDATA");
filePath = (std::filesystem::path)buffer / "PeakMenu";
std::filesystem::path logPath = filePath / "logs";
if (!std::filesystem::exists(filePath))
{
std::filesystem::create_directory(filePath);
}
else if (!std::filesystem::is_directory(filePath))
{
std::filesystem::remove(filePath);
std::filesystem::create_directory(filePath);
}
if (!std::filesystem::exists(logPath))
{
std::filesystem::create_directory(logPath);
}
else if (!std::filesystem::is_directory(logPath))
{
std::filesystem::remove(logPath);
std::filesystem::create_directory(logPath);
}
filePath /= "PeakMenu.log";
if (std::filesystem::exists(filePath))
{
tm localTime;
time_t creationDate = std::chrono::system_clock::to_time_t(std::chrono::time_point_cast<std::chrono::system_clock::duration>(std::filesystem::last_write_time(filePath) - std::filesystem::file_time_type::clock::now() + std::chrono::system_clock::now()));
localtime_s(&localTime, &creationDate);
std::ostringstream day, month, year, hour, minute, second;
day << std::setfill('0') << std::setw(2) << localTime.tm_mday;
month << "-" << std::setfill('0') << std::setw(2) << localTime.tm_mon + 1;
year << "-" << std::setfill('0') << std::setw(4) << localTime.tm_year + 1900;
hour << " " << std::setfill('0') << std::setw(2) << localTime.tm_hour;
minute << "-" << std::setfill('0') << std::setw(2) << localTime.tm_min;
second << "-" << std::setfill('0') << std::setw(2) << localTime.tm_sec;
std::filesystem::copy_file(filePath, logPath / (day.str() + month.str() + year.str() + hour.str() + minute.str() + second.str()));
}
fileOut.open(filePath, std::ios_base::out | std::ios_base::trunc);
worker->addSink(std::make_unique<Sink>(), &Sink::callback);
g3::initializeLogging(worker.get());
g3::setFatalExitHandler(&Sink::fatalCallback);
logger = this;
}
~Logger()
{
worker.reset();
FreeConsole();
logger = nullptr;
}
struct Sink
{
std::map<std::string, WORD> colors = {{SUCCESS.text, FOREGROUND_GREEN | FOREGROUND_INTENSITY}, {INFO.text, FOREGROUND_BLUE | FOREGROUND_INTENSITY}, {WARNING.text, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY}, {ERR.text, FOREGROUND_RED | FOREGROUND_INTENSITY}, {FATAL.text, FOREGROUND_RED | FOREGROUND_INTENSITY}};
void callback(g3::LogMessageMover log)
{
g3::LogMessage msg = log.get();
SetConsoleTextAttribute(logger->consoleHandle, colors.find(msg.level())->second);
std::stringstream message(msg.toString([](const g3::LogMessage&)->std::string {return ""; }));
std::string line;
std::ostringstream fmt, fileFmt;
fmt << "[" << msg.timestamp("%d/%m/%Y %H:%M:%S") << "] ";
fileFmt << "[" << msg.timestamp("%d/%m/%Y %H:%M:%S") << "] [" << msg.level() << "] ";
while (std::getline(message, line, '\n'))
{
logger->consoleOut << fmt.str() << line << std::endl << std::flush;
if (std::filesystem::exists(logger->filePath) && !std::filesystem::is_directory(logger->filePath))
{
logger->fileOut << fileFmt.str() << line << std::endl << std::flush;
}
}
}
static void fatalCallback(g3::FatalMessagePtr log)
{
SetConsoleTextAttribute(logger->consoleHandle, FOREGROUND_RED | FOREGROUND_INTENSITY);
std::stringstream message(log.get()->toString([](const g3::LogMessage&)->std::string {return ""; }));
std::string line;
std::ostringstream fmt, fileFmt;
fmt << "[" << log.get()->timestamp("%d/%m/%Y %H:%M:%S") << "] ";
fileFmt << "[" << log.get()->timestamp("%d/%m/%Y %H:%M:%S") << "] [FATAL] ";
while (std::getline(message, line, '\n'))
{
logger->consoleOut << fmt.str() << line << std::endl << std::flush;
if (std::filesystem::exists(logger->filePath) && !std::filesystem::is_directory(logger->filePath))
{
logger->fileOut << fileFmt.str() << line << std::endl << std::flush;
}
}
}
};
private:
HANDLE consoleHandle{};
std::ofstream consoleOut;
std::filesystem::path filePath;
std::ofstream fileOut;
std::unique_ptr<g3::LogWorker> worker;
};
}

View File

@@ -1,37 +0,0 @@
#include "common.hpp"
#include "logger.hpp"
#include "pointers.hpp"
BOOL WINAPI DllMain(HMODULE hmod, DWORD reason, PVOID)
{
using namespace peak;
if (reason == DLL_PROCESS_ATTACH)
{
hModule = hmod;
mainThread = CreateThread(nullptr, 0, [](PVOID) -> DWORD {
auto loggerInstance = std::make_unique<Logger>();
try
{
auto pointerInstance = std::make_unique<Pointers>();
LOG(SUCCESS) << "Patterns found.";
while (isRunning)
{
pointers->character->infiniteStamina = true;
std::this_thread::sleep_for(100ms);
}
pointers->character->infiniteStamina = false;
pointerInstance.reset();
LOG(SUCCESS) << "Removed patterns";
}
catch (std::exception& exc)
{
LOG(FATAL) << exc.what();
}
std::this_thread::sleep_for(1s);
loggerInstance.reset();
CloseHandle(mainThread);
FreeLibraryAndExitThread(hModule, 0);
}, nullptr, 0, &mainThreadId);
}
return TRUE;
}

View File

@@ -1,24 +0,0 @@
#pragma once
#include "common.hpp"
#include "logger.hpp"
namespace peak
{
class Memory
{
public:
template <typename T>
static T pointerToObject(uintptr_t pointer, std::vector<unsigned int> offsets)
{
HANDLE process = GetCurrentProcess();
uintptr_t address = (uintptr_t)GetModuleHandle(L"UnityPlayer.dll") + pointer;
for (int i = 0; i < offsets.size(); i++)
{
ReadProcessMemory(process, (BYTE*)address, &address, sizeof(address), 0);
address += offsets[i];
}
return (T)address;
}
};
}

View File

@@ -1,13 +0,0 @@
#pragma once
struct CharacterData
{
char _pad0[0x208];
float extraStamina;
};
struct Character
{
char _pad0[0xCB];
bool infiniteStamina;
};

View File

@@ -1,15 +0,0 @@
#include "pointers.hpp"
namespace peak
{
Pointers::Pointers()
{
character = Memory::pointerToObject<Character*>(0x01EB35D0, {0x430, 0x9B0, 0x10, 0xC8, 0x8, 0x110, 0x0});
pointers = this;
}
Pointers::~Pointers()
{
pointers = nullptr;
}
}

View File

@@ -1,15 +0,0 @@
#include "memory.hpp"
#include "offsets.hpp"
namespace peak
{
class Pointers
{
public:
Pointers();
~Pointers();
Character* character{};
};
inline Pointers* pointers{};
}