Here's a first attempt:
byteString[b_] :=
Which[
b < 10^3, ToString[b] <> "B",
b < 10^6, ToString[NumberForm[b/10.^3, 3]] <> "kB",
b < 10^9, ToString[NumberForm[b/10.^6, 3]] <> "MB",
True, ToString[NumberForm[b/10.^9, 3]] <> "GB"
]
handler = Replace[Hold[_, True] :> (errors = True)];
SetOptions[EvaluationNotebook[],
{
CellProlog :> (
startTime = AbsoluteTime[];
outSize = 0;
aborted = False;
$PrePrint = (
outSize += ByteCount[#];
If[MatchQ[#, $Aborted|$Aborted[]], aborted = True;];
#
) &;
errors = False;
SetOptions[EvaluationCell[],
CellDingbat -> ToBoxes@Pane[
ProgressIndicator[Appearance -> "Necklace", ImageSize -> 12],
FrameMargins -> 3
]
];
Internal`AddHandler["Message", handler];
),
CellEpilog :> (
SetOptions[EvaluationCell[],
CellDingbat -> ToBoxes@
If[outSize > 0,
Tooltip[#,
Style[Row@{byteString[outSize]}, 8.5, GrayLevel@0.3]
] &,
# &]@Style[
Column[
{
Which[
errors, Style["\[WarningSign]", 20, Red],
aborted, Style["\[WarningSign]", 20, Orange],
True, Style["✓", 20, Darker@Green]
],
Style[
GeneralUtilities`TimeString[AbsoluteTime[] - startTime],
8.5, GrayLevel@0.7
]
},
Center, -0.3
],
ShowStringCharacters -> False
]
];
$PrePrint =.;
Quiet@Internal`RemoveHandler["Message", handler];
)
}
]
Pause@1
1/0
(* Power::infy: Infinite expression 1/0 encountered. *)
(* ComplexInfinity *)
Table[i^2, {i, 100}]
(* {1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, \
225, 256, 289, 324, 361, 400, 441, 484, 529, 576, 625, 676, 729, 784, \
841, 900, 961, 1024, 1089, 1156, 1225, 1296, 1369, 1444, 1521, 1600, \
1681, 1764, 1849, 1936, 2025, 2116, 2209, 2304, 2401, 2500, 2601, \
2704, 2809, 2916, 3025, 3136, 3249, 3364, 3481, 3600, 3721, 3844, \
3969, 4096, 4225, 4356, 4489, 4624, 4761, 4900, 5041, 5184, 5329, \
5476, 5625, 5776, 5929, 6084, 6241, 6400, 6561, 6724, 6889, 7056, \
7225, 7396, 7569, 7744, 7921, 8100, 8281, 8464, 8649, 8836, 9025, \
9216, 9409, 9604, 9801, 10000} *)

This makes use of CellProlog
, CellEpilog
and $PrePrint
, together with message handlers. Some notes:
- As can be seen by the screenshot above, there are currently four different states that can be displayed: Currently running (indicated by the spinner), completed with messages (red warning sign), completed without messages (green checkmark) and aborted (orange warning sign). For completed/aborted cells, the total time is displayed, and the tooltip contains the total number of bytes of the output (if there is any)
- I first tried to use
CellEvaluationFunction
to wrap the actual evaluation. Unfortunately, we get the box structure of the entire cell like that, which makes processing rather difficult. CellProlog
and CellEpilog
on the other hand do not interfere with the actual evaluation at all, and have thus a significantly lower risk of breaking anything.
- I am using a message handler to detect if any message was actually printed during the evaluation of the cell. See this Q&A for an explanation of how they work.
- The timing is done by recording the
AbsoluteTime
before and after the evaluation.
- The results are displayed in a
CellDingbat
- I am measuring the output size by looking setting
$PrePrint
and measuring the ByteCount
of everything that will be printed.
- I check for aborted evaluations by comparing the expressions passes to
$PrePrint
to $Aborted
and $Aborted[]
. This might fail in some weird edge cases, but should mostly work.
- This approach uses
$PrePrint
, CellProlog
and CellEpilog
. So if any of those are set by some other code, this will break.
- The current version just sets the
CellProlog
and CellEpilog
options at the notebook level, but it should be easy enough to put this into a stylesheet.