Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
added: Real User Monitoring (RUM) if parameter rum-enabled=true
- Loading branch information
Showing
18 changed files
with
1,640 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
110 changes: 110 additions & 0 deletions
110
javamelody-core/src/main/java/net/bull/javamelody/CounterRequestRumData.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
/* | ||
* 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; | ||
|
||
import java.io.Serializable; | ||
|
||
/** | ||
* Données Real User Monitoring (RUM) d'une requête http. | ||
* @author Emeric Vernat | ||
*/ | ||
class CounterRequestRumData implements Serializable, Cloneable { | ||
private static final long serialVersionUID = 745110095604593659L; | ||
|
||
// au-delà de 5 minutes, on considère une valeur RUM comme aberrante et à ignorer | ||
private static final long ABERRANT_VALUE = 5 * 60 * 1000; | ||
|
||
private long hits; | ||
private long networkTimeSum; | ||
private long domProcessingSum; | ||
private long pageRenderingSum; | ||
|
||
long getHits() { | ||
return hits; | ||
} | ||
|
||
int getNetworkTimeMean() { | ||
if (hits > 0) { | ||
return (int) (networkTimeSum / hits); | ||
} | ||
return -1; | ||
} | ||
|
||
int getDomProcessingMean() { | ||
if (hits > 0) { | ||
return (int) (domProcessingSum / hits); | ||
} | ||
return -1; | ||
} | ||
|
||
int getPageRenderingMean() { | ||
if (hits > 0) { | ||
return (int) (pageRenderingSum / hits); | ||
} | ||
return -1; | ||
} | ||
|
||
void addHit(long networkTime, long domProcessing, long pageRendering) { | ||
if (networkTime < 0 || networkTime > ABERRANT_VALUE || domProcessing < 0 | ||
|| domProcessing > ABERRANT_VALUE || pageRendering < 0 | ||
|| pageRendering > ABERRANT_VALUE) { | ||
// aberrant value, we ignore it | ||
return; | ||
} | ||
|
||
networkTimeSum += networkTime; | ||
domProcessingSum += domProcessing; | ||
pageRenderingSum += pageRendering; | ||
hits++; | ||
} | ||
|
||
void addHits(CounterRequestRumData rumData) { | ||
if (rumData.hits != 0) { | ||
hits += rumData.hits; | ||
networkTimeSum += rumData.networkTimeSum; | ||
domProcessingSum += rumData.domProcessingSum; | ||
pageRenderingSum += rumData.pageRenderingSum; | ||
} | ||
} | ||
|
||
void removeHits(CounterRequestRumData rumData) { | ||
if (rumData.hits != 0) { | ||
hits -= rumData.hits; | ||
networkTimeSum -= rumData.networkTimeSum; | ||
domProcessingSum -= rumData.domProcessingSum; | ||
pageRenderingSum -= rumData.pageRenderingSum; | ||
} | ||
} | ||
|
||
/** {@inheritDoc} */ | ||
@Override | ||
public CounterRequestRumData clone() { // NOPMD | ||
try { | ||
return (CounterRequestRumData) super.clone(); | ||
} catch (final CloneNotSupportedException e) { | ||
// ne peut arriver puisque CounterRequest implémente Cloneable | ||
throw new IllegalStateException(e); | ||
} | ||
} | ||
|
||
/** {@inheritDoc} */ | ||
@Override | ||
public String toString() { | ||
return getClass().getSimpleName() + "[hits=" + hits + ']'; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
130 changes: 130 additions & 0 deletions
130
javamelody-core/src/main/java/net/bull/javamelody/HtmlInjectorResponseStream.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
/* | ||
* 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; | ||
|
||
import java.io.IOException; | ||
|
||
import javax.servlet.http.HttpServletResponse; | ||
|
||
/** | ||
* Implémentation de ServletOutputStream qui fonctionne avec le HtmlInjectorServletResponseWrapper. | ||
* @author Emeric Vernat | ||
*/ | ||
class HtmlInjectorResponseStream extends FilterServletOutputStream { | ||
private final HttpServletResponse response; | ||
private final HtmlToInject htmlToInject; | ||
private final byte[] beforeTag; | ||
private boolean injectionCanceled; | ||
|
||
interface HtmlToInject { | ||
/** | ||
* @return Html content to inject. | ||
*/ | ||
String getContent(); | ||
|
||
/** | ||
* @return Portion of html to inject content before. | ||
*/ | ||
String getBeforeTag(); | ||
} | ||
|
||
/** | ||
* Construit un servlet output stream associé avec la réponse spécifiée. | ||
* @param response HttpServletResponse | ||
* @param htmlToInject HtmlToInject | ||
* @throws IOException Erreur d'entrée/sortie | ||
*/ | ||
HtmlInjectorResponseStream(HttpServletResponse response, HtmlToInject htmlToInject) | ||
throws IOException { | ||
super(response.getOutputStream()); | ||
this.response = response; | ||
this.htmlToInject = htmlToInject; | ||
// HttpServletResponse.getCharacterEncoding() shouldn't return null according the spec. | ||
// And response.getCharacterEncoding() may not be explicit yet, | ||
// but we suppose that it does not make any difference on the beforeTag. | ||
this.beforeTag = htmlToInject.getBeforeTag().getBytes(response.getCharacterEncoding()); | ||
} | ||
|
||
void cancelInjection() { | ||
injectionCanceled = true; | ||
} | ||
|
||
// not worth it | ||
// /** {@inheritDoc} */ | ||
// @Override | ||
// public void write(int i) throws IOException { | ||
// super.write(i); | ||
// } | ||
|
||
/** {@inheritDoc} */ | ||
@Override | ||
public void write(byte[] bytes) throws IOException { | ||
write(bytes, 0, bytes.length); | ||
} | ||
|
||
/** {@inheritDoc} */ | ||
@Override | ||
public void write(byte[] bytes, int off, int len) throws IOException { | ||
// if httpResponse.setContentType(x) has been called with !x.contains("text/html"), | ||
// then no need to continue scanning for the beforeTag | ||
if (injectionCanceled) { | ||
super.write(bytes, off, len); | ||
} else { | ||
final int index = indexOf(bytes, beforeTag, off, len); | ||
if (index == -1) { | ||
// beforeTag not found yet | ||
super.write(bytes, off, len); | ||
} else { | ||
// beforeTag found: inject content. | ||
super.write(bytes, off, index); | ||
final String content = htmlToInject.getContent(); | ||
// HttpServletResponse.getCharacterEncoding() shouldn't return null according the spec | ||
super.write(content.getBytes(response.getCharacterEncoding())); | ||
super.write(bytes, off + index, len - index); | ||
} | ||
} | ||
} | ||
|
||
private static int indexOf(byte[] sourceBytes, byte[] targetBytes, int sourceOffset, | ||
int sourceLength) { | ||
final byte first = targetBytes[0]; | ||
final int max = sourceOffset + (sourceLength - targetBytes.length); | ||
|
||
for (int i = sourceOffset; i <= max; i++) { | ||
// Look for first byte | ||
while (i <= max && sourceBytes[i] != first) { | ||
i++; | ||
} | ||
|
||
if (i <= max) { | ||
// Found first byte, now look at the rest of sourceBytes | ||
int j = i + 1; | ||
final int end = j + targetBytes.length - 1; | ||
for (int k = 1; j < end && sourceBytes[j] == targetBytes[k]; k++) { | ||
j++; | ||
} | ||
|
||
if (j == end) { | ||
// Found whole bytes | ||
return i - sourceOffset; | ||
} | ||
} | ||
} | ||
return -1; | ||
} | ||
} |
Oops, something went wrong.