| /* |
| * 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) {} |
| |
| } |