blob: 623215511d281c25e2785123beb5232fe8ea9696 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more contributor license
* agreements. See the NOTICE file distributed with this work for additional information regarding
* copyright ownership. The ASF licenses this file to You 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 org.apache.geode.distributed.internal;
import static org.apache.geode.logging.internal.spi.LogWriterLevel.INFO;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.util.List;
import java.util.Set;
import org.apache.geode.GemFireIOException;
import org.apache.geode.annotations.internal.MutableForTesting;
import org.apache.geode.distributed.internal.membership.InternalDistributedMember;
import org.apache.geode.distributed.internal.membership.gms.api.Membership;
import org.apache.geode.internal.logging.InternalLogWriter;
import org.apache.geode.internal.logging.PureLogWriter;
/**
* A log intended for recording product-use.
*
* This class wraps a {@link InternalLogWriter} which it uses to record messages. It wipes the log
* when it gets too large. The size of the log file is limited to 5mb by default and can be adjusted
* with the system property <b>gemfire.max_product_use_file_size</b>, though the size is not allowed
* to be less than 1mb.
*
* @since GemFire 2013
*/
public class ProductUseLog implements MembershipListener {
@MutableForTesting
protected static long MAX_PRODUCT_USE_FILE_SIZE = Long.getLong("max_view_log_size", 5000000);
private final int logLevel;
private final File productUseLogFile;
private PureLogWriter logWriter;
private InternalDistributedSystem system;
static {
// don't allow malicious setting of the file size to something too small
if (MAX_PRODUCT_USE_FILE_SIZE < 1000000) {
MAX_PRODUCT_USE_FILE_SIZE = 1000000;
}
}
public ProductUseLog(File productUseLogFile) {
// GEODE-4180, use absolute paths
this.productUseLogFile = productUseLogFile.getAbsoluteFile();
this.logLevel = INFO.intLevel();
createLogWriter();
}
/**
* adds the log as a membership listener to the given system and logs the view when members join
*/
public void monitorUse(InternalDistributedSystem system) {
this.system = system;
DistributionManager dmgr = system.getDistributionManager();
dmgr.addMembershipListener(this);
Membership mmgr = dmgr.getMembershipManager();
if (mmgr != null) {
log("Log opened with new distributed system connection. "
+ system.getDM().getMembershipManager().getView());
} else { // membership manager not initialized?
log("Log opened with new distributed system connection. Membership view not yet available in this VM.");
}
}
public synchronized void log(String logMessage) {
if (!this.logWriter.isClosed()) {
if (this.productUseLogFile.length() + logMessage.length() + 100 > MAX_PRODUCT_USE_FILE_SIZE) {
clearLog();
}
this.logWriter.info(logMessage);
}
}
/**
* Closes the log. It may be reopened with reopen(). This does not remove the log from any
* distributed systems it is monitoring.
*/
public synchronized void close() {
if (!this.logWriter.isClosed()) {
this.logWriter.close();
}
}
/**
* returns true if the log has been closed
*/
public synchronized boolean isClosed() {
return this.logWriter.isClosed();
}
/** reopens a closed log */
public synchronized void reopen() {
if (this.logWriter.isClosed()) {
createLogWriter();
}
}
private synchronized void clearLog() {
this.logWriter.close();
this.productUseLogFile.delete();
createLogWriter();
}
private synchronized void createLogWriter() {
FileOutputStream fos;
try {
fos = new FileOutputStream(productUseLogFile, true);
} catch (FileNotFoundException ex) {
String s = String.format("Could not open log file %s.",
productUseLogFile.getAbsolutePath());
throw new GemFireIOException(s, ex);
}
PrintStream out = new PrintStream(fos);
this.logWriter = new PureLogWriter(this.logLevel, out);
}
@Override
public void memberJoined(DistributionManager distributionManager, InternalDistributedMember id) {
log("A new member joined: " + id + ". " + system.getDM().getMembershipManager().getView());
}
@Override
public void memberDeparted(DistributionManager distributionManager, InternalDistributedMember id,
boolean crashed) {}
@Override
public void memberSuspect(DistributionManager distributionManager, InternalDistributedMember id,
InternalDistributedMember whoSuspected, String reason) {}
@Override
public void quorumLost(DistributionManager distributionManager,
Set<InternalDistributedMember> failures, List<InternalDistributedMember> remaining) {}
}