It depends how the call was made.
// Interface to contract A
contract A {
function foo() public;
}
contract B {
uint public status = 0;
event logNewStatus(uint status);
function bar(address a) public {
status = 1;
logNewStatus(status);
// Call using A's interface
A contractA = A(a);
contractA.foo();
status = 2;
logNewStatus(status);
}
}
If we use the interface to call functions from contract A, and foo() fails it will undo all operations, status will remain 0, and none of the events will be recorded in the blockchain.
We can use the low level function call to have more flexibility
function bar(address a) public {
status = 1;
logNewStatus(status);
// Call using low level function
// It returns true when call have succeeded and false otherwise
bool result = a.call(bytes4(keccak256("foo()"));
if (result) {
status = 2;
logNewStatus(status);
} else {
status = 3;
logNewStatus(status);
}
}
Using call it will return true when it have succeeded, and false otherwise. So you can decide to revert changes, or to continue.
In the example there's no revert, so if the transaction fails it will set status to 3, and generate an event with the new status.