1
1
using System ;
2
+ using System . Collections . Concurrent ;
2
3
using System . Text ;
3
4
4
5
namespace AWS . Lambda . Powertools . Common ;
@@ -11,6 +12,16 @@ public class PowertoolsEnvironment : IPowertoolsEnvironment
11
12
/// </summary>
12
13
private static IPowertoolsEnvironment _instance ;
13
14
15
+ /// <summary>
16
+ /// Cached runtime environment string
17
+ /// </summary>
18
+ private static readonly string CachedRuntimeEnvironment = $ "PTENV/AWS_LAMBDA_DOTNET{ Environment . Version . Major } ";
19
+
20
+ /// <summary>
21
+ /// Cache for parsed assembly names to avoid repeated string operations
22
+ /// </summary>
23
+ private static readonly ConcurrentDictionary < string , string > ParsedAssemblyNameCache = new ( ) ;
24
+
14
25
/// <summary>
15
26
/// Gets the instance.
16
27
/// </summary>
@@ -32,41 +43,72 @@ public void SetEnvironmentVariable(string variableName, string value)
32
43
/// <inheritdoc />
33
44
public string GetAssemblyName < T > ( T type )
34
45
{
46
+ if ( type is Type typeObject )
47
+ {
48
+ return typeObject . Assembly . GetName ( ) . Name ;
49
+ }
50
+
35
51
return type . GetType ( ) . Assembly . GetName ( ) . Name ;
36
52
}
37
53
38
54
/// <inheritdoc />
39
55
public string GetAssemblyVersion < T > ( T type )
40
56
{
41
- var version = type . GetType ( ) . Assembly . GetName ( ) . Version ;
57
+ Version version ;
58
+
59
+ if ( type is Type typeObject )
60
+ {
61
+ version = typeObject . Assembly . GetName ( ) . Version ;
62
+ }
63
+ else
64
+ {
65
+ version = type . GetType ( ) . Assembly . GetName ( ) . Version ;
66
+ }
67
+
42
68
return version != null ? $ "{ version . Major } .{ version . Minor } .{ version . Build } " : string . Empty ;
43
69
}
44
70
45
71
/// <inheritdoc />
46
72
public void SetExecutionEnvironment < T > ( T type )
47
73
{
48
74
const string envName = Constants . AwsExecutionEnvironmentVariableName ;
49
- var envValue = new StringBuilder ( ) ;
50
75
var currentEnvValue = GetEnvironmentVariable ( envName ) ;
51
76
var assemblyName = ParseAssemblyName ( GetAssemblyName ( type ) ) ;
52
77
53
- // If there is an existing execution environment variable add the annotations package as a suffix.
54
- if ( ! string . IsNullOrEmpty ( currentEnvValue ) )
78
+ // Check for duplication early
79
+ if ( ! string . IsNullOrEmpty ( currentEnvValue ) && currentEnvValue . Contains ( assemblyName ) )
55
80
{
56
- // Avoid duplication - should not happen since the calling Instances are Singletons - defensive purposes
57
- if ( currentEnvValue . Contains ( assemblyName ) )
58
- {
59
- return ;
60
- }
61
-
62
- envValue . Append ( $ "{ currentEnvValue } ") ;
81
+ return ;
63
82
}
64
83
65
84
var assemblyVersion = GetAssemblyVersion ( type ) ;
85
+ var newEntry = $ "{ assemblyName } /{ assemblyVersion } ";
86
+
87
+ string finalValue ;
88
+
89
+ if ( string . IsNullOrEmpty ( currentEnvValue ) )
90
+ {
91
+ // First entry: "PT/Assembly/1.0.0 PTENV/AWS_LAMBDA_DOTNET8"
92
+ finalValue = $ "{ newEntry } { CachedRuntimeEnvironment } ";
93
+ }
94
+ else
95
+ {
96
+ // Check if PTENV already exists in one pass
97
+ var containsPtenv = currentEnvValue . Contains ( "PTENV/" ) ;
98
+
99
+ if ( containsPtenv )
100
+ {
101
+ // Just append the new entry: "existing PT/Assembly/1.0.0"
102
+ finalValue = $ "{ currentEnvValue } { newEntry } ";
103
+ }
104
+ else
105
+ {
106
+ // Append new entry + PTENV: "existing PT/Assembly/1.0.0 PTENV/AWS_LAMBDA_DOTNET8"
107
+ finalValue = $ "{ currentEnvValue } { newEntry } { CachedRuntimeEnvironment } ";
108
+ }
109
+ }
66
110
67
- envValue . Append ( $ "{ assemblyName } /{ assemblyVersion } ") ;
68
-
69
- SetEnvironmentVariable ( envName , envValue . ToString ( ) ) ;
111
+ SetEnvironmentVariable ( envName , finalValue ) ;
70
112
}
71
113
72
114
/// <summary>
@@ -75,18 +117,26 @@ public void SetExecutionEnvironment<T>(T type)
75
117
/// </summary>
76
118
/// <param name="assemblyName"></param>
77
119
/// <returns></returns>
78
- private string ParseAssemblyName ( string assemblyName )
120
+ internal static string ParseAssemblyName ( string assemblyName )
79
121
{
122
+ // Use cache to avoid repeated string operations
80
123
try
81
124
{
82
- var parsedName = assemblyName . Substring ( assemblyName . LastIndexOf ( "." , StringComparison . Ordinal ) + 1 ) ;
83
- return $ "{ Constants . FeatureContextIdentifier } /{ parsedName } ";
125
+ return ParsedAssemblyNameCache . GetOrAdd ( assemblyName , name =>
126
+ {
127
+ var lastDotIndex = name . LastIndexOf ( '.' ) ;
128
+ if ( lastDotIndex >= 0 && lastDotIndex < name . Length - 1 )
129
+ {
130
+ var parsedName = name . Substring ( lastDotIndex + 1 ) ;
131
+ return $ "{ Constants . FeatureContextIdentifier } /{ parsedName } ";
132
+ }
133
+
134
+ return $ "{ Constants . FeatureContextIdentifier } /{ name } ";
135
+ } ) ;
84
136
}
85
137
catch
86
138
{
87
- //NOOP
139
+ return string . Empty ;
88
140
}
89
-
90
- return $ "{ Constants . FeatureContextIdentifier } /{ assemblyName } ";
91
141
}
92
- }
142
+ }
0 commit comments