@@ -659,9 +659,16 @@ defmodule Ecto.Adapters.SQL do
659
659
end
660
660
661
661
defp sql_call ( adapter_meta , callback , args , params , opts ) do
662
- % { pid: pool , telemetry: telemetry , sql: sql , opts: default_opts } = adapter_meta
662
+ % {
663
+ pid: pool ,
664
+ telemetry: telemetry ,
665
+ sql: sql ,
666
+ opts: default_opts ,
667
+ log_stacktrace_mfa: log_stacktrace_mfa
668
+ } = adapter_meta
669
+
663
670
conn = get_conn_or_pool ( pool , adapter_meta )
664
- opts = with_log ( telemetry , params , opts ++ default_opts )
671
+ opts = with_log ( telemetry , log_stacktrace_mfa , params , opts ++ default_opts )
665
672
args = args ++ [ params , opts ]
666
673
apply ( sql , callback , [ conn | args ] )
667
674
end
@@ -861,6 +868,9 @@ defmodule Ecto.Adapters.SQL do
861
868
862
869
log = Keyword . get ( config , :log , :debug )
863
870
871
+ log_stacktrace_mfa =
872
+ Keyword . get ( config , :log_stacktrace_mfa , { __MODULE__ , :first_non_ecto_stacktrace , [ 1 ] } )
873
+
864
874
if log not in @ valid_log_levels do
865
875
raise """
866
876
invalid value for :log option in Repo config
@@ -872,7 +882,7 @@ defmodule Ecto.Adapters.SQL do
872
882
"""
873
883
end
874
884
875
- stacktrace = Keyword . get ( config , :stacktrace , nil )
885
+ stacktrace = Keyword . get ( config , :stacktrace )
876
886
telemetry_prefix = Keyword . fetch! ( config , :telemetry_prefix )
877
887
telemetry = { config [ :repo ] , log , telemetry_prefix ++ [ :query ] }
878
888
@@ -885,6 +895,7 @@ defmodule Ecto.Adapters.SQL do
885
895
telemetry: telemetry ,
886
896
sql: connection ,
887
897
stacktrace: stacktrace ,
898
+ log_stacktrace_mfa: log_stacktrace_mfa ,
888
899
opts: Keyword . take ( config , @ pool_opts )
889
900
}
890
901
@@ -1097,8 +1108,15 @@ defmodule Ecto.Adapters.SQL do
1097
1108
1098
1109
@ doc false
1099
1110
def reduce ( adapter_meta , statement , params , opts , acc , fun ) do
1100
- % { pid: pool , telemetry: telemetry , sql: sql , opts: default_opts } = adapter_meta
1101
- opts = with_log ( telemetry , params , opts ++ default_opts )
1111
+ % {
1112
+ pid: pool ,
1113
+ telemetry: telemetry ,
1114
+ sql: sql ,
1115
+ log_stacktrace_mfa: log_stacktrace_mfa ,
1116
+ opts: default_opts
1117
+ } = adapter_meta
1118
+
1119
+ opts = with_log ( telemetry , log_stacktrace_mfa , params , opts ++ default_opts )
1102
1120
1103
1121
case get_conn ( pool ) do
1104
1122
% DBConnection { conn_mode: :transaction } = conn ->
@@ -1113,8 +1131,15 @@ defmodule Ecto.Adapters.SQL do
1113
1131
1114
1132
@ doc false
1115
1133
def into ( adapter_meta , statement , params , opts ) do
1116
- % { pid: pool , telemetry: telemetry , sql: sql , opts: default_opts } = adapter_meta
1117
- opts = with_log ( telemetry , params , opts ++ default_opts )
1134
+ % {
1135
+ pid: pool ,
1136
+ telemetry: telemetry ,
1137
+ sql: sql ,
1138
+ opts: default_opts ,
1139
+ log_stacktrace_mfa: log_stacktrace_mfa
1140
+ } = adapter_meta
1141
+
1142
+ opts = with_log ( telemetry , log_stacktrace_mfa , params , opts ++ default_opts )
1118
1143
1119
1144
case get_conn ( pool ) do
1120
1145
% DBConnection { conn_mode: :transaction } = conn ->
@@ -1231,11 +1256,11 @@ defmodule Ecto.Adapters.SQL do
1231
1256
1232
1257
## Log
1233
1258
1234
- defp with_log ( telemetry , params , opts ) do
1235
- [ log: & log ( telemetry , params , & 1 , opts ) ] ++ opts
1259
+ defp with_log ( telemetry , log_stacktrace_mfa , params , opts ) do
1260
+ [ log: & log ( telemetry , log_stacktrace_mfa , params , & 1 , opts ) ] ++ opts
1236
1261
end
1237
1262
1238
- defp log ( { repo , log , event_name } , params , entry , opts ) do
1263
+ defp log ( { repo , log , event_name } , log_stacktrace_mfa , params , entry , opts ) do
1239
1264
% {
1240
1265
connection_time: query_time ,
1241
1266
decode_time: decode_time ,
@@ -1286,14 +1311,36 @@ defmodule Ecto.Adapters.SQL do
1286
1311
{ true , level } ->
1287
1312
Logger . log (
1288
1313
level ,
1289
- fn -> log_iodata ( measurements , repo , source , query , log_params , result , stacktrace ) end ,
1314
+ fn ->
1315
+ log_iodata (
1316
+ measurements ,
1317
+ repo ,
1318
+ source ,
1319
+ query ,
1320
+ log_params ,
1321
+ result ,
1322
+ stacktrace ,
1323
+ opts [ :log_stacktrace_mfa ] || log_stacktrace_mfa
1324
+ )
1325
+ end ,
1290
1326
ansi_color: sql_color ( query )
1291
1327
)
1292
1328
1293
1329
{ opts_level , args_level } ->
1294
1330
Logger . log (
1295
1331
opts_level || args_level ,
1296
- fn -> log_iodata ( measurements , repo , source , query , log_params , result , stacktrace ) end ,
1332
+ fn ->
1333
+ log_iodata (
1334
+ measurements ,
1335
+ repo ,
1336
+ source ,
1337
+ query ,
1338
+ log_params ,
1339
+ result ,
1340
+ stacktrace ,
1341
+ opts [ :log_stacktrace_mfa ] || log_stacktrace_mfa
1342
+ )
1343
+ end ,
1297
1344
ansi_color: sql_color ( query )
1298
1345
)
1299
1346
end
@@ -1310,7 +1357,7 @@ defmodule Ecto.Adapters.SQL do
1310
1357
defp log_measurements ( [ ] , total , acc ) ,
1311
1358
do: Map . new ( [ total_time: total ] ++ acc )
1312
1359
1313
- defp log_iodata ( measurements , repo , source , query , params , result , stacktrace ) do
1360
+ defp log_iodata ( measurements , repo , source , query , params , result , stacktrace , stacktrace_mfa ) do
1314
1361
[
1315
1362
"QUERY" ,
1316
1363
?\s ,
@@ -1324,7 +1371,7 @@ defmodule Ecto.Adapters.SQL do
1324
1371
query ,
1325
1372
?\s ,
1326
1373
inspect ( params , charlists: false ) ,
1327
- log_stacktrace ( stacktrace , repo )
1374
+ log_stacktrace ( stacktrace , repo , stacktrace_mfa )
1328
1375
]
1329
1376
end
1330
1377
@@ -1351,22 +1398,23 @@ defmodule Ecto.Adapters.SQL do
1351
1398
end
1352
1399
end
1353
1400
1354
- defp log_stacktrace ( stacktrace , repo ) do
1355
- with [ _ | _ ] <- stacktrace ,
1356
- { module , function , arity , info } <- last_non_ecto ( Enum . reverse ( stacktrace ) , repo , nil ) do
1401
+ defp log_stacktrace ( [ _ | _ ] = stacktrace , repo , { module , function , args } ) do
1402
+ entries = apply ( module , function , [ stacktrace , % { repo: repo } | args ] )
1403
+
1404
+ Enum . with_index ( entries , fn { module , function , arity , info } , idx ->
1357
1405
[
1358
1406
?\n ,
1359
1407
IO.ANSI . light_black ( ) ,
1360
- "↳ " ,
1408
+ if ( idx == 0 , do: "↳ " , else: " " ) ,
1361
1409
Exception . format_mfa ( module , function , arity ) ,
1362
1410
log_stacktrace_info ( info ) ,
1363
1411
IO.ANSI . reset ( )
1364
1412
]
1365
- else
1366
- _ -> [ ]
1367
- end
1413
+ end )
1368
1414
end
1369
1415
1416
+ defp log_stacktrace ( _ , _ , _ ) , do: [ ]
1417
+
1370
1418
defp log_stacktrace_info ( [ file: file , line: line ] ++ _ ) do
1371
1419
[ ", at: " , file , ?: , Integer . to_string ( line ) ]
1372
1420
end
@@ -1377,21 +1425,40 @@ defmodule Ecto.Adapters.SQL do
1377
1425
1378
1426
@ repo_modules [ Ecto.Repo.Queryable , Ecto.Repo.Schema , Ecto.Repo.Transaction ]
1379
1427
1380
- defp last_non_ecto ( [ { mod , _ , _ , _ } | _stacktrace ] , repo , last )
1428
+ @ doc """
1429
+ Receives a stacktrace, and return the first N items before Ecto entries
1430
+
1431
+ This function is used by default in the `:log_stacktrace_mfa` config, with
1432
+ a size of 1.
1433
+ """
1434
+ @ spec first_non_ecto_stacktrace (
1435
+ Exception . stacktrace ( ) ,
1436
+ % { repo: Ecto.Repo . t ( ) } ,
1437
+ non_neg_integer ( )
1438
+ ) :: Exception . stacktrace ( )
1439
+ def first_non_ecto_stacktrace ( stacktrace , % { repo: repo } , size ) do
1440
+ stacktrace
1441
+ |> Enum . reverse ( )
1442
+ |> last_non_ecto_entries ( repo , [ ] )
1443
+ |> Enum . take ( size )
1444
+ end
1445
+
1446
+ defp last_non_ecto_entries ( [ { mod , _ , _ , _ } | _ ] , repo , acc )
1381
1447
when mod == repo or mod in @ repo_modules ,
1382
- do: last
1448
+ do: acc
1383
1449
1384
- defp last_non_ecto ( [ last | stacktrace ] , repo , _last ) ,
1385
- do: last_non_ecto ( stacktrace , repo , last )
1450
+ defp last_non_ecto_entries ( [ entry | rest ] , repo , acc ) ,
1451
+ do: last_non_ecto_entries ( rest , repo , [ entry | acc ] )
1386
1452
1387
- defp last_non_ecto ( [ ] , _repo , last ) ,
1388
- do: last
1453
+ defp last_non_ecto_entries ( [ ] , _ , acc ) , do: acc
1389
1454
1390
1455
## Connection helpers
1391
1456
1392
1457
defp checkout_or_transaction ( fun , adapter_meta , opts , callback ) do
1393
- % { pid: pool , telemetry: telemetry , opts: default_opts } = adapter_meta
1394
- opts = with_log ( telemetry , [ ] , opts ++ default_opts )
1458
+ % { pid: pool , telemetry: telemetry , opts: default_opts , log_stacktrace_mfa: log_stacktrace_mfa } =
1459
+ adapter_meta
1460
+
1461
+ opts = with_log ( telemetry , log_stacktrace_mfa , [ ] , opts ++ default_opts )
1395
1462
1396
1463
callback = fn conn ->
1397
1464
previous_conn = put_conn ( pool , conn )
0 commit comments