11using System ;
2+ using System . Collections . Concurrent ;
23using System . Text ;
34
45namespace AWS . Lambda . Powertools . Common ;
@@ -11,6 +12,16 @@ public class PowertoolsEnvironment : IPowertoolsEnvironment
1112 /// </summary>
1213 private static IPowertoolsEnvironment _instance ;
1314
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+
1425 /// <summary>
1526 /// Gets the instance.
1627 /// </summary>
@@ -32,41 +43,72 @@ public void SetEnvironmentVariable(string variableName, string value)
3243 /// <inheritdoc />
3344 public string GetAssemblyName < T > ( T type )
3445 {
46+ if ( type is Type typeObject )
47+ {
48+ return typeObject . Assembly . GetName ( ) . Name ;
49+ }
50+
3551 return type . GetType ( ) . Assembly . GetName ( ) . Name ;
3652 }
3753
3854 /// <inheritdoc />
3955 public string GetAssemblyVersion < T > ( T type )
4056 {
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+
4268 return version != null ? $ "{ version . Major } .{ version . Minor } .{ version . Build } " : string . Empty ;
4369 }
4470
4571 /// <inheritdoc />
4672 public void SetExecutionEnvironment < T > ( T type )
4773 {
4874 const string envName = Constants . AwsExecutionEnvironmentVariableName ;
49- var envValue = new StringBuilder ( ) ;
5075 var currentEnvValue = GetEnvironmentVariable ( envName ) ;
5176 var assemblyName = ParseAssemblyName ( GetAssemblyName ( type ) ) ;
5277
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 ) )
5580 {
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 ;
6382 }
6483
6584 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+ }
66110
67- envValue . Append ( $ "{ assemblyName } /{ assemblyVersion } ") ;
68-
69- SetEnvironmentVariable ( envName , envValue . ToString ( ) ) ;
111+ SetEnvironmentVariable ( envName , finalValue ) ;
70112 }
71113
72114 /// <summary>
@@ -75,18 +117,26 @@ public void SetExecutionEnvironment<T>(T type)
75117 /// </summary>
76118 /// <param name="assemblyName"></param>
77119 /// <returns></returns>
78- private string ParseAssemblyName ( string assemblyName )
120+ internal static string ParseAssemblyName ( string assemblyName )
79121 {
122+ // Use cache to avoid repeated string operations
80123 try
81124 {
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+ } ) ;
84136 }
85137 catch
86138 {
87- //NOOP
139+ return string . Empty ;
88140 }
89-
90- return $ "{ Constants . FeatureContextIdentifier } /{ assemblyName } ";
91141 }
92- }
142+ }
0 commit comments