@@ -99,6 +99,8 @@ use opentelemetry::{
99
99
logs:: { AnyValue , LogRecord , Logger , LoggerProvider , Severity } ,
100
100
Key ,
101
101
} ;
102
+ #[ cfg( feature = "experimental_metadata_attributes" ) ]
103
+ use opentelemetry_semantic_conventions:: trace:: { CODE_FILEPATH , CODE_LINENO , CODE_NAMESPACE } ;
102
104
use std:: borrow:: Cow ;
103
105
104
106
pub struct OpenTelemetryLogBridge < P , L >
@@ -130,6 +132,28 @@ where
130
132
log_record. set_severity_number ( severity_of_level ( record. level ( ) ) ) ;
131
133
log_record. set_severity_text ( record. level ( ) . as_str ( ) ) ;
132
134
log_record. set_body ( AnyValue :: from ( record. args ( ) . to_string ( ) ) ) ;
135
+
136
+ #[ cfg( feature = "experimental_metadata_attributes" ) ]
137
+ {
138
+ if let Some ( filepath) = record. file ( ) {
139
+ log_record. add_attribute (
140
+ Key :: new ( CODE_FILEPATH ) ,
141
+ AnyValue :: from ( filepath. to_string ( ) ) ,
142
+ ) ;
143
+ }
144
+
145
+ if let Some ( line_no) = record. line ( ) {
146
+ log_record. add_attribute ( Key :: new ( CODE_LINENO ) , AnyValue :: from ( line_no) ) ;
147
+ }
148
+
149
+ if let Some ( module) = record. module_path ( ) {
150
+ log_record. add_attribute (
151
+ Key :: new ( CODE_NAMESPACE ) ,
152
+ AnyValue :: from ( module. to_string ( ) ) ,
153
+ ) ;
154
+ }
155
+ }
156
+
133
157
log_record. add_attributes ( log_attributes ( record. key_values ( ) ) ) ;
134
158
log_record. set_target ( record. metadata ( ) . target ( ) . to_string ( ) ) ;
135
159
@@ -1127,6 +1151,54 @@ mod tests {
1127
1151
}
1128
1152
}
1129
1153
1154
+ #[ cfg( feature = "experimental_metadata_attributes" ) ]
1155
+ #[ test]
1156
+ fn logbridge_code_attributes ( ) {
1157
+ use opentelemetry_semantic_conventions:: trace:: {
1158
+ CODE_FILEPATH , CODE_LINENO , CODE_NAMESPACE ,
1159
+ } ;
1160
+
1161
+ let exporter = InMemoryLogsExporter :: default ( ) ;
1162
+
1163
+ let logger_provider = LoggerProvider :: builder ( )
1164
+ . with_simple_exporter ( exporter. clone ( ) )
1165
+ . build ( ) ;
1166
+
1167
+ let otel_log_appender = OpenTelemetryLogBridge :: new ( & logger_provider) ;
1168
+
1169
+ otel_log_appender. log (
1170
+ & log:: RecordBuilder :: new ( )
1171
+ . level ( log:: Level :: Warn )
1172
+ . args ( format_args ! ( "WARN" ) )
1173
+ . file ( Some ( "src/main.rs" ) )
1174
+ . module_path ( Some ( "service" ) )
1175
+ . line ( Some ( 101 ) )
1176
+ . build ( ) ,
1177
+ ) ;
1178
+
1179
+ let logs = exporter. get_emitted_logs ( ) . unwrap ( ) ;
1180
+
1181
+ let get = |needle : & str | -> Option < AnyValue > {
1182
+ logs[ 0 ] . record . attributes_iter ( ) . find_map ( |( k, v) | {
1183
+ if k. as_str ( ) == needle {
1184
+ Some ( v. clone ( ) )
1185
+ } else {
1186
+ None
1187
+ }
1188
+ } )
1189
+ } ;
1190
+
1191
+ assert_eq ! (
1192
+ Some ( AnyValue :: String ( StringValue :: from( "src/main.rs" ) ) ) ,
1193
+ get( CODE_FILEPATH )
1194
+ ) ;
1195
+ assert_eq ! (
1196
+ Some ( AnyValue :: String ( StringValue :: from( "service" ) ) ) ,
1197
+ get( CODE_NAMESPACE )
1198
+ ) ;
1199
+ assert_eq ! ( Some ( AnyValue :: Int ( 101 ) ) , get( CODE_LINENO ) ) ;
1200
+ }
1201
+
1130
1202
#[ test]
1131
1203
fn test_flush ( ) {
1132
1204
let exporter = InMemoryLogsExporter :: default ( ) ;
0 commit comments