net.sf.eBusx.monitor.package-info Maven / Gradle / Ivy
//
// Copyright 2012 Charles W. Rapp
//
// 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.
//
/**
* This package provides the ability to instrument
* {@link net.sf.eBus.client.EObject eBus objects} and to monitor
* those objects' on-going state and transient events.
*
* An on-going state is one that persists over time. An example
* is a disconnected connection. This state continues until
* either re-established or explicitly closed by the application.
* A transient event occurs in an instant, with no on-going
* impact to the application. An example of a transient event
* would be the application catching exception from which it
* immediately recovers. This exception is reported as a
* transient event so administrators are aware of the problem.
*
*
* Both on-going status and transient events are reported with
* a given
* {@link net.sf.eBusx.monitor.ActionLevel action level}.
* This action level
* informs administrators about the event severity. The need to
* report
* {@link net.sf.eBusx.monitor.ActionLevel#POSSIBLE_ACTION},
* {@link net.sf.eBusx.monitor.ActionLevel#ACTION_REQUIRED} and
* {@link net.sf.eBusx.monitor.ActionLevel#FATAL_ERROR} events is
* obvious: there is a problem occurring which must be corrected.
* But there is debate about reporting
* {@link net.sf.eBusx.monitor.ActionLevel#NO_ACTION},
* information-only events. One view is that an application may
* be considered to be operating correctly unless stated
* otherwise. The opposing view is that,
* "if it goes without saying, then it goes even better with
* saying it." By reporting "no action" events, it is an
* explicit statement of correct operation.
*
* Instrumenting your Application
* The starting point is to
* {@link net.sf.eBusx.monitor.Monitor#openMonitor(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, net.sf.eBus.messages.EField) open a monitor}
* with your host, application name, version, copyright,
* description and optional name/value attributes. This method
* should be called once at system start. See
* {@link net.sf.eBusx.monitor.Monitor#openMonitor(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, net.sf.eBus.messages.EField) Monitor.openMonitor}
* for a detailed explanation for each of the parameters.
*
* The next step in application instrumentation is to
* {@link net.sf.eBusx.monitor.Monitor#register(net.sf.eBus.client.EObject) register your eBus objects}
* with the {@code Monitor} instance. You obtain the
* {@code Monitor} instance either from
* {@code Monitor.openMonitor} or
* {@link net.sf.eBusx.monitor.Monitor#getMonitor()} (
* note: {@code Monitor.getMonitor()} returns
* {@code null} if monitor was not opened).
* {@link net.sf.eBus.client.EObject#name() EObject.name()} is
* used to uniquely identify this object. A newly registered
* eBus object's initial on-going status is set to:
*
*
* -
* Action level: {@link net.sf.eBusx.monitor.ActionLevel#NO_ACTION NO_ACTION}
*
* -
* Action name: Registered
*
* -
* Action message: "Registered with monitor subsystem"
*
*
*
* Once registered, an object may
* {@link net.sf.eBusx.monitor.Monitor#update(net.sf.eBusx.monitor.ActionLevel, String, String, net.sf.eBus.client.EObject) update}
* its on-going (persistent) state and report
* {@link net.sf.eBusx.monitor.Monitor#transientStatus(net.sf.eBusx.monitor.ActionLevel, String, String, net.sf.eBus.client.EObject) transient events}
* via the {@code Monitor} instance. This is demonstrated in the
* following code:
*
* import net.sf.eBusx.monitor.ActionLevel;
import net.sf.eBusx.monitor.Monitor
// Note Monitor.getMonitor() returns null if Monitor was not opened.
final Monitor monitor = Monitor.getMonitor();
// This example assumes this eBus object is registered with Monitor.
// Note: this state is on-going until corrected.
monitor.update(ActionLevel.ACTION_REQUIRED,
"Market data feed",
"Ticker plant market data feed is DOWN.",
this);
// This is an example of a transient status report - not an on-going issue.
monitor.transientStatus(ActionLevel.ACTION_REQUIRED,
"Market data feed",
"Ticker plant market data feed down for " + downTimeInterval,
this);
// When the problem is resolved, then be sure to update the on-going status.
monitor.update(ActionLevel.NO_ACTION,
"Market data feed",
"Ticker plant market data feed is up.",
this);
*
* If a registered object is to be discarded prior
* to application termination, it should be
* {@link net.sf.eBusx.monitor.Monitor#deregister(net.sf.eBus.client.EObject) deregistered}.
* {@code Monitor} reports this de-registration by setting the
* final on-going status to:
*
*
* -
* Action level: {@code NO_ACTION}
*
* -
* Action name: Deregistered
*
* -
* Action message: "Deregistered from monitor subsystem"
*
*
*
* Please note that {@code Monitor} maintains a weak reference to
* the registered eBus object. If a registered eBus object is
* garbage collected, then {@code Monitor} will automatically
* de-register this eBus object.
*
*
* {@code Monitor} reports object registration, on-going updates,
* transient updates, and de-registration using
* {@link net.sf.eBusx.monitor.MonitorUpdate MonitorUpdate}
* notification message which contains:
* {@link net.sf.eBusx.monitor.MonitorId} and
* {@link net.sf.eBusx.monitor.MonitorUpdate.UpdateType}.
*
*
* -
* host name ({@code String}),
*
* -
* application name ({@code String}),
*
* -
* monitor instance ({@link net.sf.eBusx.monitor.MonitorId MonitorId}),
*
* -
* update type ({@link net.sf.eBusx.monitor.MonitorUpdate.UpdateType UpdateType})
* which specifies if eBus object is registered, on-going
* status changed, transient status, and de-registered,
*
* -
* action level ({@link net.sf.eBusx.monitor.ActionLevel ActionLevel})
*
* -
* action name ({@code String}), and
*
* -
* action message ({@code String}).
*
*
*
* These {@code MonitorUpdate} messages are published to the
* subject
* "/eBus/monitor/update/<host name>/<application name>"
* where <host name> and
* <application name> are those used to open the
* application's {@code Monitor} instance. {@code Monitor} also
* replies to
* {@link net.sf.eBusx.monitor.ApplicationInfoRequest ApplicationInfoRequest}
* and
* {@link net.sf.eBusx.monitor.MonitoredObjectRequest MonitoredObjectRequest}
* messages. {@code ApplicationInfoRequest} sends a
* {@link net.sf.eBusx.monitor.ApplicationInfoReply ApplicationInfoReply}
* containing the application host name, application name, etc.
* {@code MonitoredObjectRequest} sends a
* {@link net.sf.eBusx.monitor.MonitoredObjectReply MonitoredObjectReply}
* containing the latest
* {@link net.sf.eBusx.monitor.PersistentStatusMessage PersistentStatusMessage}
* for all currently registered eBus objects.
*
*
* This leads to the next section.
*
* Monitoring eBus applications
* 1. Connect to Remote eBus Applications
*
* Establish a
* {@link net.sf.eBus.client.ERemoteApp remote connection} to
* all eBus applications which will be monitored.
*
* 2. Subscribe to Monitor Updates
*
* As mentioned above, {@code Monitor} publishes
* {@code ApplicationInfo} and {@code MonitorUpdate} messages on
* a patterned subject
* {@link net.sf.eBusx.monitor.Monitor#MONITOR_UPDATE_FORMAT MONITOR_UPDATE_FORMAT}.
* If {@link net.sf.eBus.client.ESubscribeFeed ESubscribeFeed} is
* used receive monitor updates, then the subscriber must know
* all host name, application name pairs. That is, the monitored
* hosts and application is fixed and known a prior to
* subscribing. It also means that there must be a way to add
* or remove host, application name pairs if monitoring is
* dynamic.
*
*
* eBus provides a way to subscribe to all monitor update
* subjects rather than each specific host, application name
* pair:
* {@link net.sf.eBus.client.EMultiSubscribeFeed EMultiSubscribeFeed}
* using an {@link net.sf.eBus.util.regex.Pattern eBus pattern}
* as the "subject". The following code demonstrates how to use
* an {@code EMultiSubscribeFeed} to receive monitor updates:
*
* import static net.sf.eBus.client.EFeed.FeedScope;
import net.sf.eBus.client.EMultiSubscribeFeed;
import net.sf.eBus.client.IESubscribeFeed;
import net.sf.eBus.util.regex.Pattern;
import net.sf.eBusx.monitor.ApplicationInfo;
import net.sf.eBusx.monitor.Monitor;
import net.sf.eBusx.monitor.MonitorUpdate;
private EMultiSubscribeFeed mAppInfoFeed;
private EMultiSubscribeFeed mUpdateFeed;
@Override public void startup() {
final Pattern multiUpdateSubject =
Pattern.compile(
// Put ".+" in host and application name subject portions to accept
// updates from all hosts and applications.
String.format(Monitor.MONITOR_UPDATE_FORMAT, ".+", ".+"));
mAppInfoFeed =
(EMultiSubscribeFeed.builder()).target(this)
.messageClass(ApplicationInfo.class)
.scope(FeedScope.LOCAL_AND_REMOTE)
.query(multiUpdateSubject)
.statusCallback(this::onAppInfoFeedStatus)
.notifyCallback(this::onAppInfoUpdate)
.build();
mUpdateFeed =
(EMultiSubscribeFeed.builder()).target(this)
.messageClass(MonitorUpdate.class)
.scope(FeedScope.LOCAL_AND_REMOTE)
.query(multiUpdateSubject)
.statusCallback(this::onUpdateFeedStatus)
.notifyCallback(this::onMonitorUpdate)
.build();
}
private void onAppInfoFeedStatus(final EFeedState state, final IESubscribeFeed feed) {
...
}
private void onAppInfoUpdate(final ApplicationInfo info, final IESubscribeFeed feed) {
...
}
private void onUpdateFeedStatus(final EFeedState state, final IESubscribeFeed feed) {
...
}
private void onMonitorUpdate(final MonitorUpdate update, final IESubscribeFeed ffed) {
...
}
*
* It is recommended that subscriptions be put into place before
* requesting latest monitor updates which is the next step.
*
* 3. Request Latest Monitor Updates
*
* Unlike monitor notification subject, the monitor request
* subjects are fixed:
* {@link net.sf.eBusx.monitor.Monitor#APP_INFO_REQUEST_SUBJECT APP_INFO_REQUEST_SUBJECT}
* and
* {@link net.sf.eBusx.monitor.Monitor#ONGOING_REQUEST_SUBJECT ONGOING_REQUEST_SUBJECT}.
* It is recommended that these request subjects be put into
* place on start-up but the requests themselves not be made
* until the repliers are known to be up. The following code
* demonstrates how to do this:
*
* import static net.sf.eBus.client.EFeed.FeedScope;
import net.sf.eBus.client.ERequestFeed;
import net.sf.eBus.messages.EMessageKey;
import net.sf.eBusx.monitor.ApplicationInfoRequest;
import net.sf.eBusx.monitor.Monitor;
import net.sf.eBusx.monitor.MonitorObjectRequest;
private ERequestFeed mAppInfoRequestFeed;
private ERequestFeed.ERequest mAppInfoRequest;
private ERequestFeed mMonitorRequestFeed;
private ERequestFeed.ERequest mMonitorRequest;
@Override public void startup() {
final EMessageKey appInfoRequestKey =
new EMessageKey(
ApplicationInfoRequest.class, Monitor.APP_INFO_REQUEST_SUBJECT);
final EMessageKey ogRequestKey =
new EMessageKey(
MonitoredObjectRequest.class, Monitor.ONGOING_REQUEST_SUBJECT);
mAppInfoRequestFeed =
(ERequestFeed.builder()).target(this)
.messageKey(appInfoRequestKey)
.scope(FeedScope.LOCAL_AND_REMOTE)
.statusCallback(this::onAppInfoRequestFeedStatus)
.replyCallback(this::onAppInfoReply)
.build();
mAppInfoRequestFeed.subscribe();
mMonitorRequestFeed =
(ERequestFeed.builder()).target(this)
.messageKey(ogRequestKey)
.scope(FeedScope.LOCAL_AND_REMOTE)
.statusCallback(this::onMonitorFeedStatus)
.replyCallback(this::onMonitorStatusReply)
.build();
mMonitorRequestFeed.subscribe();
}
private void onAppInfoRequestFeedStatus(final EFeedState state, final IESubscribeFeed feed) {
if (state == EFeedState.UP) {
mAppInfoRequest =
mAppInfoRequestFeed.request(
(ApplicationInfoRequest.builder()).subject(Monitor.APP_INFO_REQUEST_SUBJECT)
.build());
}
}
private void onAppInfoReply(final int remaining, final EReplyMessage msg, final ERequestFeed.Request request) {
// Process application information reply.
}
private void onMonitorFeedStatus(final EFeedState state, final IESubscribeFeed feed) {
if (state == EFeedState.UP) {
mMonitorRequest =
mMonitorRequestFeed.request(
(MonitoredObjectRequest.builder()).subject(Monitor.ONGOING_REQUEST_SUBJECT)
.build());
}
}
private void onMonitorStatusReply(final int remaining, final EReplyMessage msg, final ERequestFeed.ERequest request) {
// Process monitored object status reply.
}
*/
package net.sf.eBusx.monitor;