/* * Copyright 2010 Fred Sauer * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.allen_sauer.gwt.log.client; import com.google.gwt.core.client.GWT; import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.rpc.ServiceDefTarget; import com.allen_sauer.gwt.log.shared.LogRecord; import java.util.ArrayList; /** * Logger which sends log records via GWT RPC to the server where it can be deobfuscated and logged. */ public final class RemoteLoggerImpl extends RemoteLogger { // CHECKSTYLE_JAVADOC_OFF private static final RemoteLoggerConfig config = GWT.create(RemoteLoggerConfig.class); /** * Delay after first log message is received before firing RPC. */ private static final int MESSAGE_QUEUEING_DELAY_MILLIS = 100; private static final String REMOTE_LOGGER_NAME = "Remote Logger"; private final Timer batchDeliveryTimer = new Timer() { @Override public void run() { service.log(logRecordList, callback); logRecordList.clear(); } }; private final AsyncCallback<ArrayList<LogRecord>> callback; private boolean callInProgressOrScheduled = false; private Throwable failure; private final ArrayList<LogRecord> logRecordList = new ArrayList<LogRecord>(); private final RemoteLoggerServiceAsync service; public RemoteLoggerImpl() { if (!GWT.isClient()) { throw new UnsupportedOperationException(); } service = (RemoteLoggerServiceAsync) GWT.create(RemoteLoggerService.class); final ServiceDefTarget target = (ServiceDefTarget) service; String serviceEntryPointUrl = config.serviceEntryPointUrl(); if (serviceEntryPointUrl != null) { target.setServiceEntryPoint(serviceEntryPointUrl); } callback = new AsyncCallback<ArrayList<LogRecord>>() { @Override public void onFailure(Throwable ex) { String serviceEntryPoint = ((ServiceDefTarget) service).getServiceEntryPoint(); GWT.log(REMOTE_LOGGER_NAME + " has failed to contact servlet at " + serviceEntryPoint, ex); GWT.log(REMOTE_LOGGER_NAME + " has suspended with " + logRecordList.size() + " log message(s) not delivered", null); failure = ex; callInProgressOrScheduled = false; } @Override public void onSuccess(ArrayList<LogRecord> deobfuscatedLogRecords) { if (GWT.isProdMode() && deobfuscatedLogRecords != null) { for (LogRecord record : deobfuscatedLogRecords) { if (record.getThrowable() != null) { RemoteLoggerImpl.super.loggersLog(record); } } } callInProgressOrScheduled = false; maybeTriggerRPC(); } }; } @Override public void clear() { } @Override public boolean isSupported() { return true; } @Override public void log(LogRecord record) { super.loggersLog(record); if (failure != null) { // remote logger has been disabled return; } if (record.getLevel() == Log.LOG_LEVEL_OFF) { // don't forward gwt-log diagnostic messages to the server return; } logRecordList.add(record); maybeTriggerRPC(); } @Override public void loggersLog(LogRecord record) { log(record); } @Override public void setCurrentLogLevel(int level) { } private void maybeTriggerRPC() { if (failure == null && !callInProgressOrScheduled && !logRecordList.isEmpty()) { // allow a few log messages to accumulate before firing RPC batchDeliveryTimer.schedule(MESSAGE_QUEUEING_DELAY_MILLIS); callInProgressOrScheduled = true; } } }