Skip to content

Commit 742d232

Browse files
authored
fix: Fix a crash that can occur when the profiler logs certain characters. (#1982) (#2109)
1 parent 2d8da68 commit 742d232

File tree

7 files changed

+102
-1
lines changed

7 files changed

+102
-1
lines changed

src/Agent/NewRelic/Home/Home.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
</Target>
1414

1515
<ItemGroup>
16-
<PackageReference Include="NewRelic.Agent.Internal.Profiler" Version="10.18.0.15"/>
16+
<PackageReference Include="NewRelic.Agent.Internal.Profiler" Version="10.20.0.8"/>
1717
</ItemGroup>
1818

1919
</Project>

src/Agent/NewRelic/Profiler/Profiler/CorProfilerCallbackImpl.h

+3
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <string>
2424
#include <thread>
2525
#include <utility>
26+
#include <codecvt>
2627

2728
#ifdef PAL_STDCPP_COMPAT
2829
#include "UnixSystemCalls.h"
@@ -1091,6 +1092,8 @@ namespace NewRelic { namespace Profiler {
10911092
xstring_t logfilename(nrlog::DefaultFileLogLocation(_systemCalls).GetPathAndFileName());
10921093
std::string wlogfilename(std::begin(logfilename), std::end(logfilename));
10931094
nrlog::StdLog.get_dest().open(wlogfilename);
1095+
// Imbue with locale and codecvt facet is used to allow the log file to write non-ascii chars to the log
1096+
nrlog::StdLog.get_dest().imbue(std::locale(std::locale::classic(), new std::codecvt_utf8<wchar_t>));
10941097
nrlog::StdLog.get_dest().exceptions(std::wostream::failbit | std::wostream::badbit);
10951098
LogInfo("Logger initialized.");
10961099
}

tests/Agent/IntegrationTests/ContainerApplications/SmokeTestApp/Controllers/WeatherForecastController.cs

+19
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@
44
using System;
55
using System.Collections.Generic;
66
using System.Linq;
7+
using System.Runtime.CompilerServices;
8+
using System.Threading;
79
using Microsoft.AspNetCore.Mvc;
810
using Microsoft.Extensions.Logging;
11+
using NewRelic.Api.Agent;
912

1013
namespace ContainerizedAspNetCoreApp.Controllers;
1114

@@ -28,6 +31,9 @@ public WeatherForecastController(ILogger<WeatherForecastController> logger)
2831
[HttpGet]
2932
public IEnumerable<WeatherForecast> Get()
3033
{
34+
// This name of this method call contains characters outside of the ascii
35+
// range of characters.
36+
MethodWithSpecialCharacter\u0435();
3137
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
3238
{
3339
Date = DateTime.Now.AddDays(index),
@@ -36,4 +42,17 @@ public IEnumerable<WeatherForecast> Get()
3642
})
3743
.ToArray();
3844
}
45+
46+
/// <summary>
47+
/// The е in Mеthod is not a normal e character, it is char code \u0435.
48+
/// This method is used to validate that we support instrumenting methods
49+
/// with these types of names, and that the profiler does not crash.
50+
/// </summary>
51+
[Trace]
52+
[MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
53+
private void MethodWithSpecialCharacter\u0435()
54+
{
55+
// This just similates doing a blocking external call
56+
Thread.Sleep(100);
57+
}
3958
}

tests/Agent/IntegrationTests/ContainerApplications/SmokeTestApp/SmokeTestApp.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
<ItemGroup>
1111
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.17.2" />
12+
<PackageReference Include="NewRelic.Agent.Api" Version="10.20.0" />
1213
</ItemGroup>
1314

1415
</Project>

tests/Agent/IntegrationTests/ContainerApplications/docker-compose.yml

+4
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,10 @@ services:
6767
service: smoketestapp
6868
build:
6969
dockerfile: SmokeTestApp/Dockerfile.amazon
70+
LinuxUnicodeLogFileApp:
71+
extends:
72+
file: docker-compose-smoketestapp.yml
73+
service: smoketestapp
7074

7175
networks:
7276
default:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright 2020 New Relic, Inc. All rights reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
namespace NewRelic.Agent.ContainerIntegrationTests.ContainerFixtures
5+
{
6+
public class LinuxUnicodeLogFileTestFixture : LinuxSmokeTestFixtureBase
7+
{
8+
private static readonly string Dockerfile = "SmokeTestApp/Dockerfile";
9+
private static readonly string ApplicationDirectoryName = "LinuxUnicodeLogfileTestApp";
10+
private static readonly ContainerApplication.Architecture Architecture = ContainerApplication.Architecture.X64;
11+
private static readonly string DistroTag = "jammy";
12+
13+
public LinuxUnicodeLogFileTestFixture() : base(ApplicationDirectoryName, DistroTag, Architecture, Dockerfile) { }
14+
}
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// Copyright 2020 New Relic, Inc. All rights reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
using NewRelic.Agent.IntegrationTestHelpers;
5+
using Xunit.Abstractions;
6+
using Xunit;
7+
using NewRelic.Agent.ContainerIntegrationTests.ContainerFixtures;
8+
using System;
9+
10+
namespace ContainerIntegrationTests
11+
{
12+
/// <summary>
13+
/// This test is meant to prevent any regressions from occurring when profiler log lines containing
14+
/// character codes outside of the ascii range are written to log files. Older profiler versions
15+
/// could trigger an error or crash when this happened. Before the profiler change, no transactions
16+
/// would be created by the test application, with the profiler change, the test transaction should be
17+
/// created successfully.
18+
/// </summary>
19+
public class LinuxUnicodeLogFileTest : NewRelicIntegrationTest<DebianX64SmokeTestFixture>
20+
{
21+
private readonly DebianX64SmokeTestFixture _fixture;
22+
23+
public LinuxUnicodeLogFileTest(DebianX64SmokeTestFixture fixture, ITestOutputHelper output) : base(fixture)
24+
{
25+
_fixture = fixture;
26+
_fixture.TestLogger = output;
27+
28+
_fixture.Actions(setupConfiguration: () =>
29+
{
30+
var configModifier = new NewRelicConfigModifier(_fixture.DestinationNewRelicConfigFilePath);
31+
configModifier.ConfigureFasterMetricsHarvestCycle(10);
32+
// The original problem only seemed to occur with some of the finest level log lines
33+
// and it did not occur with console logs.
34+
configModifier.SetLogLevel("finest");
35+
},
36+
exerciseApplication: () =>
37+
{
38+
_fixture.ExerciseApplication();
39+
40+
_fixture.Delay(11); // wait long enough to ensure a metric harvest occurs after we exercise the app
41+
_fixture.AgentLog.WaitForLogLine(AgentLogBase.HarvestFinishedLogLineRegex, TimeSpan.FromSeconds(11));
42+
43+
// shut down the container and wait for the agent log to see it
44+
_fixture.ShutdownRemoteApplication();
45+
_fixture.AgentLog.WaitForLogLine(AgentLogBase.ShutdownLogLineRegex, TimeSpan.FromSeconds(10));
46+
});
47+
48+
_fixture.Initialize();
49+
}
50+
51+
[Fact]
52+
public void Test()
53+
{
54+
var actualMetrics = _fixture.AgentLog.GetMetrics();
55+
56+
Assert.Contains(actualMetrics, m => m.MetricSpec.Name.Equals("WebTransaction/MVC/WeatherForecast/Get"));
57+
}
58+
}
59+
}

0 commit comments

Comments
 (0)