Skip to content

Commit f6b686c

Browse files
committed
Add templating for logs feature
1 parent 69ec1e8 commit f6b686c

5 files changed

Lines changed: 634 additions & 0 deletions

File tree

dart/lib/src/sentry_logger.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,16 @@ import 'protocol/sentry_log.dart';
55
import 'protocol/sentry_log_level.dart';
66
import 'protocol/sentry_log_attribute.dart';
77
import 'sentry_options.dart';
8+
import 'sentry_logger_formatter.dart';
89

910
class SentryLogger {
1011
SentryLogger(this._clock, {Hub? hub}) : _hub = hub ?? HubAdapter();
1112

1213
final ClockProvider _clock;
1314
final Hub _hub;
1415

16+
late final fmt = SentryLoggerFormatter(this);
17+
1518
FutureOr<void> trace(
1619
String body, {
1720
Map<String, SentryLogAttribute>? attributes,
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
import 'dart:async';
2+
import 'protocol/sentry_log_attribute.dart';
3+
import 'sentry_template_string.dart';
4+
import 'sentry_logger.dart';
5+
6+
class SentryLoggerFormatter {
7+
SentryLoggerFormatter(this._logger);
8+
9+
final SentryLogger _logger;
10+
11+
FutureOr<void> trace(
12+
String templateBody,
13+
List<dynamic> arguments, {
14+
Map<String, SentryLogAttribute>? attributes,
15+
}) {
16+
final templateString = SentryTemplateString(templateBody);
17+
final interpolatedBody = templateString.format(arguments);
18+
final allAttributes = _getTemplateAttributes(templateBody, arguments);
19+
if (attributes != null) {
20+
allAttributes.addAll(attributes);
21+
}
22+
return _logger.trace(interpolatedBody, attributes: allAttributes);
23+
}
24+
25+
FutureOr<void> debug(
26+
String templateBody,
27+
List<dynamic> arguments, {
28+
Map<String, SentryLogAttribute>? attributes,
29+
}) {
30+
final templateString = SentryTemplateString(templateBody);
31+
final interpolatedBody = templateString.format(arguments);
32+
final allAttributes = _getTemplateAttributes(templateBody, arguments);
33+
if (attributes != null) {
34+
allAttributes.addAll(attributes);
35+
}
36+
return _logger.debug(interpolatedBody, attributes: allAttributes);
37+
}
38+
39+
FutureOr<void> info(
40+
String templateBody,
41+
List<dynamic> arguments, {
42+
Map<String, SentryLogAttribute>? attributes,
43+
}) {
44+
final templateString = SentryTemplateString(templateBody);
45+
final interpolatedBody = templateString.format(arguments);
46+
final allAttributes = _getTemplateAttributes(templateBody, arguments);
47+
if (attributes != null) {
48+
allAttributes.addAll(attributes);
49+
}
50+
return _logger.info(interpolatedBody, attributes: allAttributes);
51+
}
52+
53+
FutureOr<void> warn(
54+
String templateBody,
55+
List<dynamic> arguments, {
56+
Map<String, SentryLogAttribute>? attributes,
57+
}) {
58+
final templateString = SentryTemplateString(templateBody);
59+
final interpolatedBody = templateString.format(arguments);
60+
final allAttributes = _getTemplateAttributes(templateBody, arguments);
61+
if (attributes != null) {
62+
allAttributes.addAll(attributes);
63+
}
64+
return _logger.warn(interpolatedBody, attributes: allAttributes);
65+
}
66+
67+
FutureOr<void> error(
68+
String templateBody,
69+
List<dynamic> arguments, {
70+
Map<String, SentryLogAttribute>? attributes,
71+
}) {
72+
final templateString = SentryTemplateString(templateBody);
73+
final interpolatedBody = templateString.format(arguments);
74+
final allAttributes = _getTemplateAttributes(templateBody, arguments);
75+
if (attributes != null) {
76+
allAttributes.addAll(attributes);
77+
}
78+
return _logger.error(interpolatedBody, attributes: allAttributes);
79+
}
80+
81+
FutureOr<void> fatal(
82+
String templateBody,
83+
List<dynamic> arguments, {
84+
Map<String, SentryLogAttribute>? attributes,
85+
}) {
86+
final templateString = SentryTemplateString(templateBody);
87+
final interpolatedBody = templateString.format(arguments);
88+
final allAttributes = _getTemplateAttributes(templateBody, arguments);
89+
if (attributes != null) {
90+
allAttributes.addAll(attributes);
91+
}
92+
return _logger.fatal(interpolatedBody, attributes: allAttributes);
93+
}
94+
95+
// Helper
96+
97+
Map<String, SentryLogAttribute> _getTemplateAttributes(
98+
String templateBody, List<dynamic> args) {
99+
final templateAttributes = {
100+
'sentry.message.template': SentryLogAttribute.string(templateBody),
101+
};
102+
for (var i = 0; i < args.length; i++) {
103+
final argument = args[i];
104+
final key = 'sentry.message.parameter.$i';
105+
if (argument is String) {
106+
templateAttributes[key] = SentryLogAttribute.string(argument);
107+
} else if (argument is int) {
108+
templateAttributes[key] = SentryLogAttribute.int(argument);
109+
} else if (argument is bool) {
110+
templateAttributes[key] = SentryLogAttribute.bool(argument);
111+
} else if (argument is double) {
112+
templateAttributes[key] = SentryLogAttribute.double(argument);
113+
} else {
114+
try {
115+
templateAttributes[key] =
116+
SentryLogAttribute.string(argument.toString());
117+
} catch (e) {
118+
templateAttributes[key] = SentryLogAttribute.string("");
119+
}
120+
}
121+
}
122+
123+
return templateAttributes;
124+
}
125+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
class SentryTemplateString {
2+
SentryTemplateString(this.template);
3+
4+
final String template;
5+
6+
String format(List<dynamic> arguments) {
7+
if (arguments.isEmpty) {
8+
// If no arguments provided, replace all %s with empty strings
9+
return template.replaceAll('%s', '');
10+
}
11+
12+
final result = StringBuffer();
13+
int argIndex = 0;
14+
int templateIndex = 0;
15+
16+
while (templateIndex < template.length) {
17+
if (templateIndex + 1 < template.length &&
18+
template[templateIndex] == '%' &&
19+
template[templateIndex + 1] == '%') {
20+
// Found %% - escape sequence, output single %
21+
result.write('%');
22+
// Skip %%
23+
templateIndex += 2;
24+
} else if (templateIndex + 1 < template.length &&
25+
template[templateIndex] == '%' &&
26+
template[templateIndex + 1] == 's') {
27+
// Found %s placeholder
28+
if (argIndex < arguments.length) {
29+
// Convert argument to string
30+
final arg = arguments[argIndex];
31+
result.write(_convertToString(arg));
32+
argIndex++;
33+
} else {
34+
// Not enough arguments, replace with empty string
35+
result.write('');
36+
}
37+
// Skip %s
38+
templateIndex += 2;
39+
} else {
40+
// Regular character, copy as is
41+
result.write(template[templateIndex]);
42+
templateIndex++;
43+
}
44+
}
45+
return result.toString();
46+
}
47+
48+
String _convertToString(dynamic value) {
49+
if (value is String) {
50+
return value;
51+
} else {
52+
try {
53+
return value.toString();
54+
} catch (e) {
55+
// If toString() fails, return empty string
56+
return '';
57+
}
58+
}
59+
}
60+
}

0 commit comments

Comments
 (0)