Skip to content

Commit

Permalink
javamelody#692 warn in the reports if multiple instances use the same…
Browse files Browse the repository at this point in the history
… storage directory
  • Loading branch information
evernat authored and elnggng committed Mar 17, 2022
1 parent 64d8f8a commit 68bc3b5
Show file tree
Hide file tree
Showing 10 changed files with 130 additions and 3 deletions.
Expand Up @@ -35,6 +35,7 @@
import javax.management.MBeanServer;
import javax.management.ObjectName;

import net.bull.javamelody.internal.common.I18N;
import net.bull.javamelody.internal.common.LOG;
import net.bull.javamelody.internal.common.Parameters;
import net.bull.javamelody.internal.model.Collector;
Expand Down Expand Up @@ -252,6 +253,10 @@ private void initCollect() {
return;
}

if (collector.isStorageUsedByMultipleInstances()) {
LOG.info(I18N.getString("storage_used_by_multiple_instances"));
}

try {
JRobin.initBackendFactory(timer);
} catch (final IOException e) {
Expand Down
Expand Up @@ -74,6 +74,7 @@ public class Collector { // NOPMD
private final boolean noDatabase = Parameters.isNoDatabase();
private List<MetricsPublisher> metricsPublishers;
private final WebappVersions webappVersions;
private final StorageLock storageLock;

/**
* Constructeur.
Expand Down Expand Up @@ -130,6 +131,9 @@ public Collector(String application, List<Counter> counters,
+ Parameters.getStorageDirectory(application), e);
}

// puis pose le lock
this.storageLock = new StorageLock(application);

this.webappVersions = new WebappVersions(application);
}

Expand Down Expand Up @@ -985,11 +989,19 @@ void clearCounter(String counterName) {
}
}

public boolean isStorageUsedByMultipleInstances() {
return !storageLock.isAcquired();
}

public void stop() {
try {
// on persiste les compteurs pour les relire à l'initialisation et ne pas perdre les stats
for (final Counter counter : counters) {
counter.writeToFile();
try {
// on persiste les compteurs pour les relire à l'initialisation et ne pas perdre les stats
for (final Counter counter : counters) {
counter.writeToFile();
}
} finally {
storageLock.release();
}
} catch (final IOException e) {
// persistance échouée, tant pis
Expand Down
@@ -0,0 +1,84 @@
/*
* Copyright 2008-2017 by Emeric Vernat
*
* This file is part of Java Melody.
*
* 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 net.bull.javamelody.internal.model;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.channels.OverlappingFileLockException;

import net.bull.javamelody.internal.common.Parameters;

/**
* Lock sur le répertoire de stockage pour détecter si des instances distinctes écrivent dans le même répertoire.
* @author Emeric Vernat
*/
class StorageLock {
private static final String LOCK_FILENAME = "javamelody.lock";
private final RandomAccessFile input;
private final FileChannel fileChannel;
private FileLock fileLock;

StorageLock(String application) {
super();
final File storageDir = Parameters.getStorageDirectory(application);
final File lockFile = new File(storageDir, LOCK_FILENAME);
try {
this.input = new RandomAccessFile(lockFile, "rw");
this.fileChannel = input.getChannel();
} catch (final FileNotFoundException e) {
throw new IllegalArgumentException(e);
}
// initialize the lock
getFileLock();
}

void release() throws IOException {
try {
if (fileLock != null) {
fileLock.release();
}
} finally {
try {
fileChannel.close();
} finally {
input.close();
}
}
}

private FileLock getFileLock() {
if (fileLock == null) {
try {
fileLock = fileChannel.tryLock();
} catch (final IOException e) {
return null;
} catch (final OverlappingFileLockException e) {
return null;
}
}
return fileLock;
}

boolean isAcquired() {
return getFileLock() != null;
}
}
Expand Up @@ -499,6 +499,11 @@ private void writeGraphs() throws IOException {
writeln("</div>");
return;
}
if (collector.isStorageUsedByMultipleInstances()) {
writeln("<div align='center' class='severe'><br/><br/>");
writeln("#storage_used_by_multiple_instances#");
writeln("</div><br/>");
}

writeGraphs(collector.getDisplayedCounterJRobins());
final Collection<JRobin> otherJRobins = collector.getDisplayedOtherJRobins();
Expand Down
Expand Up @@ -208,6 +208,12 @@ private void writeGraphs(Collection<JRobin> jrobins, Map<String, byte[]> mySmall
addToDocument(jrobinParagraph);
return;
}
if (collector.isStorageUsedByMultipleInstances()) {
final String message = getString("storage_used_by_multiple_instances") + "\n\n";
final Paragraph jrobinParagraph = new Paragraph(message, PdfFonts.BOLD.getFont());
jrobinParagraph.setAlignment(Element.ALIGN_CENTER);
addToDocument(jrobinParagraph);
}
final Paragraph jrobinParagraph = new Paragraph("",
FontFactory.getFont(FontFactory.HELVETICA, 9f, Font.NORMAL));
jrobinParagraph.setAlignment(Element.ALIGN_CENTER);
Expand Down
Expand Up @@ -621,3 +621,6 @@ Tableau_de_bord=Dashboard

collect_server_misusage=Do not use this monitoring page if you use the optional collector server: \
either use the monitoring page from the webapp, without a collector server, or use the page from the collector server

storage_used_by_multiple_instances=Do not use the same storage directory with multiple instances or it will cause data loss. \
Configure the storage-directory parameter if needed.
Expand Up @@ -621,3 +621,6 @@ Tableau_de_bord=

collect_server_misusage=Nutzen Sie nicht diese Monitoring Seite, wenn Sie den optionalen collector server benutzen: \
Bitte nutzen Sie stattdessen entweder die Monitoring Seite der webapp ohne einen collector server oder benutzen Sie die eigene Monitoring Seite des collector servers.

storage_used_by_multiple_instances=Do not use the same storage directory with multiple instances or it will cause data loss. \
Configure the storage-directory parameter if needed.
Expand Up @@ -620,3 +620,6 @@ Tableau_de_bord=Tableau de bord

collect_server_misusage=N'utilisez pas cette page de monitoring si vous utilisez le serveur de collecte optionnel : \
utilisez soit la page de monitoring de cette webapp, sans un serveur de collecte, ou utilisez la page du serveur de collecte

storage_used_by_multiple_instances=N'utilisez pas le même répertoire de stockage pour plusieurs instances ou cela causera des pertes de données. \
Configurez le paramètre storage-directory si besoin.
Expand Up @@ -625,3 +625,6 @@ Tableau_de_bord=Painel principal

collect_server_misusage=Não use esta página de monitoramento se você usar o servidor coletor opcional: \
use a página de monitoramento do webapp, Sem um collector server, ou use a página do collector server

storage_used_by_multiple_instances=Do not use the same storage directory with multiple instances or it will cause data loss. \
Configure the storage-directory parameter if needed.
Expand Up @@ -947,3 +947,6 @@ thread_interrupt_sent = Thread interrupt signal sent
send_thread_interrupt=Send a thread interrupt signal to {0}. The thread can test Thread.currentThread().isInterrupted() to stop itself.
confirm_send_thread_interrupt=Do you confirm the sending of a thread interrupt signal to {0}?
Interrupt=Interrupt

storage_used_by_multiple_instances=Do not use the same storage directory with multiple instances or it will cause data loss. \
Configure the storage-directory parameter if needed.

0 comments on commit 68bc3b5

Please sign in to comment.