При переносе JSF-портлетов с Liferay 6.2 на Liferay 7.1 обнаружилось неприятное поведение - далеко не все исключения, происходящие при работе при работе приложения, фиксируются в логах. Некоторые из них отображаются на странице, другие не отображаются вообще нигде. Были обнаружены следующие ситуации:
	- @PostConstruct методы- исключение отображается только на странице.
- action'ы у не-AJAX компонентов - исключение не отображается вообще.
- Исключения при рендере ответа (например, EL-ValueExpression бросило исключение) - ошибки отображаются на странице.
@PostConstruct
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
@ManagedBean
@ViewScoped
public class InitFailureBean {
    @PostConstruct
    private void init() {
        throw new RuntimeException("HELLO THERE!");
    }
    public String getProp() {
        return "Hello, cruel world!";
    }
}
view.xhtml
<f:view
        xmlns="http://www.w3.org/1999/xhtml"
        xmlns:f="http://xmlns.jcp.org/jsf/core"
        xmlns:h="http://xmlns.jcp.org/jsf/html"
>
    <h:head/>
    <h:body>
        <h:outputText value="#{initFailureBean.prop}"/>
    </h:body>
</f:view>

CommandButton action
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
@ManagedBean
@ViewScoped
public class AjaxFailureBean {
    public static final Log log = LogFactoryUtil.getLog(AjaxFailureBean.class);
    public void actionFailure() {
        log.info("There will be an error");
        if (true) {
            throw new RuntimeException("Invisible error!");
        }
        log.info("After exception");
    }
}
<f:view
        xmlns="http://www.w3.org/1999/xhtml"
        xmlns:f="http://xmlns.jcp.org/jsf/core"
        xmlns:h="http://xmlns.jcp.org/jsf/html"
        xmlns:p="http://primefaces.org/ui"
        xmlns:ui="http://java.sun.com/jsf/facelets"
>
    <h:body>
        <h:form>
            <p:commandButton value="Action failure!" ajax="false" action="#{ajaxFailureBean.actionFailure}" update="sampleOutput"/>
        </h:form>
    </h:body>
</f:view>
Страница после нажатия кнопки

Содержимое лога после трёх нажатий кнопки 

Исключение при рендере
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
@ManagedBean
@ViewScoped
public class RenderFailureBean {
    public static final Log log = LogFactoryUtil.getLog(RenderFailureBean.class);
    public String getFailureProp() {
        log.info("Before exception");
        if (true) {
            throw new RuntimeException("Exception here!");
        }
        log.info("After exception");
        return "Hello, cruel world!";
    }
}
<f:view
        xmlns="http://www.w3.org/1999/xhtml"
        xmlns:f="http://xmlns.jcp.org/jsf/core"
        xmlns:h="http://xmlns.jcp.org/jsf/html"
        xmlns:p="http://primefaces.org/ui"
        xmlns:ui="http://java.sun.com/jsf/facelets"
>
    <h:body>
        <h:form>
            <h:outputText value="#{renderFailureBean.failureProp}"/>
        </h:form>
    </h:body>
</f:view>
Страница после ошибки:

Логи после ошибки:

Решение проблемы
Для решения этой проблемы был написан простой обработчик исключений JSF, добавляющий сообщения об ошибке в логи.
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import javax.faces.FacesException;
import javax.faces.context.ExceptionHandler;
import javax.faces.context.ExceptionHandlerWrapper;
import javax.faces.event.ExceptionQueuedEvent;
public class LiferayJsfExceptionLogger extends ExceptionHandlerWrapper {
    private static final Log log = LogFactoryUtil.getLog(LiferayJsfExceptionLogger.class);
    private ExceptionHandler wrapped;
    public LiferayJsfExceptionLogger(ExceptionHandler wrapped) {
        this.wrapped = wrapped;
    }
    @Override
    public ExceptionHandler getWrapped() {
        return wrapped;
    }
    @Override
    public void handle() throws FacesException {
        for (ExceptionQueuedEvent event : getUnhandledExceptionQueuedEvents()) {
            Throwable throwable = event.getContext().getException();
            log.error(throwable);
        }
        super.handle();
    }
}
import javax.faces.context.ExceptionHandler;
import javax.faces.context.ExceptionHandlerFactory;
public class LiferayJsfExceptionLoggerFactory extends ExceptionHandlerFactory {
    private final ExceptionHandlerFactory parent;
    public LiferayJsfExceptionLoggerFactory(ExceptionHandlerFactory parent) {
        this.parent = parent;
    }
    @Override
    public ExceptionHandler getExceptionHandler() {
        return new LiferayJsfExceptionLogger(parent.getExceptionHandler());
    }
}
<?xml version="1.0"?>
<faces-config
	version="2.2"
	xmlns="http://xmlns.jcp.org/xml/ns/javaee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd"
>
	<factory>
		<exception-handler-factory>com.tuneit.ibox.jsf.LiferayJsfExceptionLoggerFactory</exception-handler-factory>
	</factory>
</faces-config>
Кроме того, всё это можно оформить в виде отдельной библиотеки и подключать её, как зависимость  - тогда отпадёт потребность в ручной регистрации фабрики в faces-config.xml.

Проверяем предыдущие примеры (например, с ошибкой при рендере).
Страница:

Логи:

 
Засим откланиваюсь, прощайте.