nstream.reflect.agent.MetaAgent Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of nstream-reflect Show documentation
Show all versions of nstream-reflect Show documentation
Web Agent introspection runtime
// Copyright 2015-2024 Nstream, inc.
//
// Licensed under the Redis Source Available License 2.0 (RSALv2) Agreement;
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://redis.com/legal/rsalv2-agreement/
//
// 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 nstream.reflect.agent;
import java.util.concurrent.atomic.AtomicLongFieldUpdater;
import nstream.reflect.Meta;
import nstream.reflect.model.LinkStats;
import nstream.reflect.model.LogEntry;
import swim.api.lane.DemandLane;
import swim.api.lane.SupplyLane;
import swim.api.lane.function.OnCue;
import swim.api.warp.WarpUplink;
import swim.concurrent.Cont;
import swim.structure.Value;
import swim.system.LinkBinding;
import swim.system.NodeContext;
import swim.system.agent.AgentNode;
import swim.uri.Uri;
import swim.warp.Envelope;
public abstract class MetaAgent extends AgentNode {
protected final LinkStats linkTotal = new LinkStats();
protected final LinkStats linkDelta = new LinkStats();
volatile DemandLane linkStats;
volatile SupplyLane traceLog;
volatile SupplyLane debugLog;
volatile SupplyLane infoLog;
volatile SupplyLane warnLog;
volatile SupplyLane errorLog;
volatile SupplyLane failLog;
volatile long bubbleTime;
public MetaAgent() {
// nop
}
public abstract Meta meta();
@Override
public void setNodeContext(NodeContext nodeContext) {
super.setNodeContext(nodeContext);
openLanes();
}
protected void openLanes() {
final DemandLane linkStats = demandLane()
.valueForm(LinkStats.form())
.observe(new MetaLinkStatsController(this));
openLane(LINK_STATS_URI, linkStats);
this.linkStats = linkStats;
final SupplyLane traceLog = supplyLane()
.valueForm(LogEntry.form());
openLane(TRACE_LOG_URI, traceLog);
this.traceLog = traceLog;
final SupplyLane debugLog = supplyLane()
.valueForm(LogEntry.form());
openLane(DEBUG_LOG_URI, debugLog);
this.debugLog = debugLog;
final SupplyLane infoLog = supplyLane()
.valueForm(LogEntry.form());
openLane(INFO_LOG_URI, infoLog);
this.infoLog = infoLog;
final SupplyLane warnLog = supplyLane()
.valueForm(LogEntry.form());
openLane(WARN_LOG_URI, warnLog);
this.warnLog = warnLog;
final SupplyLane errorLog = supplyLane()
.valueForm(LogEntry.form());
openLane(ERROR_LOG_URI, errorLog);
this.errorLog = errorLog;
final SupplyLane failLog = supplyLane()
.valueForm(LogEntry.form());
openLane(FAIL_LOG_URI, failLog);
this.failLog = failLog;
}
public LinkStats linkStats() {
return this.linkTotal.get();
}
public void didOpenDownlink(LinkBinding link) {
this.linkTotal.didOpenDownlink(link);
this.linkDelta.didOpenDownlink(link);
didUpdateStats();
}
public void didCloseDownlink(LinkBinding link) {
this.linkTotal.didCloseDownlink(link);
this.linkDelta.didCloseDownlink(link);
didUpdateStats();
}
public void didOpenUplink(LinkBinding link) {
this.linkTotal.didOpenUplink(link);
this.linkDelta.didOpenUplink(link);
didUpdateStats();
}
public void didCloseUplink(Value linkKey) {
this.linkTotal.didCloseUplink(linkKey);
this.linkDelta.didCloseUplink(linkKey);
didUpdateStats();
}
public void didPushDown(Envelope envelope) {
this.linkTotal.didPushDown(envelope);
this.linkDelta.didPushDown(envelope);
didUpdateStats();
}
public void didPushUp(Envelope envelope) {
this.linkTotal.didPushUp(envelope);
this.linkDelta.didPushUp(envelope);
didUpdateStats();
}
public void setLinkStats(LinkStats stats) {
stats.supersede(this.linkTotal, this.linkDelta);
didUpdateStats();
}
public void accumulateLinkStats(LinkStats stats) {
this.linkTotal.accumulate(stats);
this.linkDelta.accumulate(stats);
didUpdateStats();
}
public void didUpdateStats() {
do {
final long oldBubbleTime = this.bubbleTime;
final long newBubbleTime = System.currentTimeMillis();
if (newBubbleTime - oldBubbleTime >= BUBBLE_INTERVAL) {
if (BUBBLE_TIME.compareAndSet(this, oldBubbleTime, newBubbleTime)) {
try {
bubbleStats();
cueStats();
} catch (Throwable error) {
if (Cont.isNonFatal(error)) {
didFail(error);
} else {
throw error;
}
}
break;
}
} else {
break;
}
} while (true);
}
public void bubbleStats() {
bubbleLinkStats();
}
protected void bubbleLinkStats() {
final Meta metaParent = meta().metaParent();
if (metaParent != null) {
final MetaAgent parentAgent = metaParent.metaAgent();
parentAgent.accumulateLinkStats(this.linkDelta.getAndReset());
}
}
public void cueStats() {
cueLinkStats();
}
protected void cueLinkStats() {
final DemandLane linkStats = this.linkStats;
if (linkStats != null) {
linkStats.cue();
}
}
public void didLogTrace(LogEntry entry) {
try {
final SupplyLane traceLog = this.traceLog;
if (traceLog != null) {
traceLog.push(entry);
}
bubbleTraceLog(entry);
} catch (Throwable error) {
if (Cont.isNonFatal(error)) {
didFail(error);
} else {
throw error;
}
}
}
protected void bubbleTraceLog(LogEntry entry) {
final Meta metaParent = meta().metaParent();
if (metaParent != null) {
final MetaAgent parentAgent = metaParent.metaAgent();
parentAgent.didLogTrace(entry);
}
}
public void didLogDebug(LogEntry entry) {
try {
final SupplyLane debugLog = this.debugLog;
if (debugLog != null) {
debugLog.push(entry);
}
bubbleDebugLog(entry);
} catch (Throwable error) {
if (Cont.isNonFatal(error)) {
didFail(error);
} else {
throw error;
}
}
}
protected void bubbleDebugLog(LogEntry entry) {
final Meta metaParent = meta().metaParent();
if (metaParent != null) {
final MetaAgent parentAgent = metaParent.metaAgent();
parentAgent.didLogDebug(entry);
}
}
public void didLogInfo(LogEntry entry) {
try {
final SupplyLane infoLog = this.infoLog;
if (infoLog != null) {
infoLog.push(entry);
}
bubbleInfoLog(entry);
} catch (Throwable error) {
if (Cont.isNonFatal(error)) {
didFail(error);
} else {
throw error;
}
}
}
protected void bubbleInfoLog(LogEntry entry) {
final Meta metaParent = meta().metaParent();
if (metaParent != null) {
final MetaAgent parentAgent = metaParent.metaAgent();
parentAgent.didLogInfo(entry);
}
}
public void didLogWarn(LogEntry entry) {
try {
final SupplyLane warnLog = this.warnLog;
if (warnLog != null) {
warnLog.push(entry);
}
bubbleWarnLog(entry);
} catch (Throwable error) {
if (Cont.isNonFatal(error)) {
didFail(error);
} else {
throw error;
}
}
}
protected void bubbleWarnLog(LogEntry entry) {
final Meta metaParent = meta().metaParent();
if (metaParent != null) {
final MetaAgent parentAgent = metaParent.metaAgent();
parentAgent.didLogWarn(entry);
}
}
public void didLogError(LogEntry entry) {
try {
final SupplyLane errorLog = this.errorLog;
if (errorLog != null) {
errorLog.push(entry);
}
bubbleErrorLog(entry);
} catch (Throwable error) {
if (Cont.isNonFatal(error)) {
didFail(error);
} else {
throw error;
}
}
}
protected void bubbleErrorLog(LogEntry entry) {
final Meta metaParent = meta().metaParent();
if (metaParent != null) {
final MetaAgent parentAgent = metaParent.metaAgent();
parentAgent.didLogError(entry);
}
}
public void didLogFail(LogEntry entry) {
try {
final SupplyLane failLog = this.failLog;
if (failLog != null) {
failLog.push(entry);
}
bubbleFailLog(entry);
} catch (Throwable error) {
if (Cont.isNonFatal(error)) {
didFail(error);
} else {
throw error;
}
}
}
protected void bubbleFailLog(LogEntry entry) {
final Meta metaParent = meta().metaParent();
if (metaParent != null) {
final MetaAgent parentAgent = metaParent.metaAgent();
parentAgent.didLogFail(entry);
}
}
@Override
public void close() {
super.close();
bubbleStats();
}
static final Uri LINK_STATS_URI = Uri.parse("linkStats");
static final Uri TRACE_LOG_URI = Uri.parse("traceLog");
static final Uri DEBUG_LOG_URI = Uri.parse("debugLog");
static final Uri INFO_LOG_URI = Uri.parse("infoLog");
static final Uri WARN_LOG_URI = Uri.parse("warnLog");
static final Uri ERROR_LOG_URI = Uri.parse("errorLog");
static final Uri FAIL_LOG_URI = Uri.parse("failLog");
static final long BUBBLE_INTERVAL = 1000L;
static final AtomicLongFieldUpdater BUBBLE_TIME =
AtomicLongFieldUpdater.newUpdater(MetaAgent.class, "bubbleTime");
}
final class MetaLinkStatsController implements OnCue {
final MetaAgent agent;
MetaLinkStatsController(MetaAgent agent) {
this.agent = agent;
}
@Override
public LinkStats onCue(WarpUplink uplink) {
return this.agent.linkStats();
}
}