Skip to content

Commit 95adbb1

Browse files
committed
refactor profiler to support http with html crawling in additional to local filesystem #798
1 parent b2d6bed commit 95adbb1

21 files changed

+650
-179
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package fr.adrienbrault.idea.symfony2plugin.profiler;
2+
3+
import com.intellij.openapi.project.Project;
4+
import fr.adrienbrault.idea.symfony2plugin.profiler.dict.ProfilerRequestInterface;
5+
import org.jetbrains.annotations.NotNull;
6+
7+
import java.util.ArrayList;
8+
import java.util.Collections;
9+
import java.util.List;
10+
11+
/**
12+
* @author Daniel Espendiller <daniel@espendiller.net>
13+
*/
14+
public class HttpProfilerIndex implements ProfilerIndexInterface {
15+
16+
@NotNull
17+
private final Project project;
18+
19+
@NotNull
20+
private final String url;
21+
22+
public HttpProfilerIndex(@NotNull Project project, @NotNull String url) {
23+
this.project = project;
24+
this.url = url;
25+
}
26+
27+
@NotNull
28+
@Override
29+
public List<ProfilerRequestInterface> getRequests() {
30+
String content = ProfilerUtil.getProfilerUrlContent(this.url);
31+
if(content == null) {
32+
return Collections.emptyList();
33+
}
34+
35+
return new ArrayList<>(ProfilerUtil.collectHttpDataForRequest(
36+
project, ProfilerUtil.createRequestsFromIndexHtml(this.project, content))
37+
);
38+
}
39+
}
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,54 @@
11
package fr.adrienbrault.idea.symfony2plugin.profiler;
22

3+
import com.intellij.openapi.project.Project;
34
import fr.adrienbrault.idea.symfony2plugin.profiler.dict.ProfilerRequest;
5+
import fr.adrienbrault.idea.symfony2plugin.profiler.dict.ProfilerRequestInterface;
6+
import org.jetbrains.annotations.NotNull;
47
import org.jetbrains.annotations.Nullable;
58

69
import java.io.BufferedReader;
710
import java.io.File;
811
import java.io.FileReader;
912
import java.io.IOException;
1013
import java.util.ArrayList;
14+
import java.util.List;
1115

12-
public class ProfilerIndex {
13-
16+
/**
17+
* @author Daniel Espendiller <daniel@espendiller.net>
18+
*/
19+
public class LocalProfilerIndex implements ProfilerIndexInterface {
20+
@NotNull
1421
private File file;
1522

16-
public ProfilerIndex(File file) {
23+
public LocalProfilerIndex(@NotNull File file) {
1724
this.file = file;
1825
}
1926

20-
public ArrayList<ProfilerRequest> getRequests() {
21-
ArrayList<ProfilerRequest> list = new ArrayList<>();
22-
23-
String trennzeichen = ",";
24-
27+
@NotNull
28+
public List<ProfilerRequestInterface> getRequests() {
29+
List<ProfilerRequestInterface> list = new ArrayList<>();
2530
try {
2631
BufferedReader in = new BufferedReader(new FileReader(this.file));
2732
String readString;
2833
while ((readString = in.readLine()) != null) {
29-
list.add(new ProfilerRequest(readString.split(trennzeichen), this));
34+
list.add(new ProfilerRequest(readString.split(","), this));
3035
}
3136

3237
in.close();
3338
} catch (IOException ignored) {
34-
3539
}
3640

37-
3841
return list;
3942
}
4043

41-
public String getPath(ProfilerRequest profilerRequest) {
44+
@NotNull
45+
public String getPath(@NotNull ProfilerRequestInterface profilerRequest) {
4246
String[] hash = profilerRequest.getHash().split("(?<=\\G.{2})");
43-
4447
return hash[2] + "/" + hash[1] + "/" + profilerRequest.getHash();
45-
4648
}
4749

4850
@Nullable
49-
public File getFile(ProfilerRequest profilerRequest) {
51+
public File getFile(@NotNull ProfilerRequestInterface profilerRequest) {
5052
String path = this.getPath(profilerRequest);
5153

5254
File file = new File(this.file.getParentFile().getAbsolutePath() + "/" + path);
@@ -59,8 +61,8 @@ public File getFile(ProfilerRequest profilerRequest) {
5961
}
6062

6163
@Nullable
62-
public ProfilerRequest getRequestOnHash(String hash) {
63-
for(ProfilerRequest profilerRequest :this.getRequests()) {
64+
public ProfilerRequestInterface getRequestOnHash(@NotNull String hash) {
65+
for(ProfilerRequestInterface profilerRequest :this.getRequests()) {
6466
if(profilerRequest.getHash().equals(hash)) {
6567
return profilerRequest;
6668
}
@@ -70,7 +72,7 @@ public ProfilerRequest getRequestOnHash(String hash) {
7072
}
7173

7274
@Nullable
73-
public String getContent(ProfilerRequest profilerRequest) {
75+
public String getContent(@NotNull ProfilerRequestInterface profilerRequest) {
7476
File file = this.getFile(profilerRequest);
7577
if(file == null) {
7678
return null;
@@ -88,8 +90,6 @@ public String getContent(ProfilerRequest profilerRequest) {
8890
} catch (IOException ignored) {
8991
}
9092

91-
9293
return content.toString();
9394
}
94-
9595
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package fr.adrienbrault.idea.symfony2plugin.profiler;
2+
3+
import fr.adrienbrault.idea.symfony2plugin.profiler.dict.ProfilerRequestInterface;
4+
import org.jetbrains.annotations.NotNull;
5+
6+
import java.util.List;
7+
8+
/**
9+
* @author Daniel Espendiller <daniel@espendiller.net>
10+
*/
11+
public interface ProfilerIndexInterface {
12+
@NotNull
13+
List<ProfilerRequestInterface> getRequests();
14+
}

src/fr/adrienbrault/idea/symfony2plugin/profiler/ProfilerUtil.java

+101-9
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,21 @@
11
package fr.adrienbrault.idea.symfony2plugin.profiler;
22

3+
import com.google.common.cache.Cache;
4+
import com.google.common.cache.CacheBuilder;
35
import com.intellij.lang.html.HTMLLanguage;
6+
import com.intellij.openapi.application.ApplicationManager;
47
import com.intellij.openapi.project.Project;
5-
import com.intellij.openapi.util.Condition;
68
import com.intellij.psi.PsiElement;
79
import com.intellij.psi.PsiFileFactory;
810
import com.intellij.psi.impl.source.html.HtmlFileImpl;
9-
import com.intellij.psi.search.PsiElementProcessor;
10-
import com.intellij.psi.util.PsiElementFilter;
1111
import com.intellij.psi.util.PsiTreeUtil;
1212
import com.intellij.psi.xml.XmlTag;
1313
import com.intellij.psi.xml.XmlTagValue;
14-
import com.intellij.util.containers.ContainerUtil;
1514
import fr.adrienbrault.idea.symfony2plugin.Symfony2ProjectComponent;
16-
import fr.adrienbrault.idea.symfony2plugin.profiler.dict.ProfilerRequest;
15+
import fr.adrienbrault.idea.symfony2plugin.profiler.dict.HttpCollectorProfilerRequest;
16+
import fr.adrienbrault.idea.symfony2plugin.profiler.dict.HttpDefaultDataCollector;
17+
import fr.adrienbrault.idea.symfony2plugin.profiler.dict.HttpProfilerRequest;
18+
import fr.adrienbrault.idea.symfony2plugin.profiler.dict.ProfilerRequestInterface;
1719
import org.apache.commons.lang.ArrayUtils;
1820
import org.apache.commons.lang.StringUtils;
1921
import org.jetbrains.annotations.NotNull;
@@ -26,10 +28,19 @@
2628
import java.net.URLConnection;
2729
import java.nio.charset.StandardCharsets;
2830
import java.util.*;
31+
import java.util.concurrent.*;
2932
import java.util.stream.Collectors;
3033

3134
public class ProfilerUtil {
3235

36+
/**
37+
* Cache for url content
38+
*/
39+
private static Cache<String, String> REQUEST_CACHE = CacheBuilder.newBuilder()
40+
.maximumSize(50)
41+
.expireAfterWrite(5, TimeUnit.MINUTES)
42+
.build();
43+
3344
@Nullable
3445
public static File findProfilerCsv(Project project) {
3546

@@ -50,7 +61,7 @@ public static File findProfilerCsv(Project project) {
5061
public static String getProfilerIndexViaHttp(@NotNull String url) {
5162
URLConnection conn;
5263
try {
53-
conn = new URL("http://127.0.0.1:8000/_profiler/empty/search/results?ip=&limit=10").openConnection();
64+
conn = new URL(url + "?limit=10").openConnection();
5465
} catch (IOException e) {
5566
return null;
5667
}
@@ -67,7 +78,7 @@ public static String getProfilerIndexViaHttp(@NotNull String url) {
6778
* We dont have complete xpath with html support inside so reuse internal html parser
6879
*/
6980
@NotNull
70-
public static Collection<ProfilerRequest> createRequestsFromIndexHtml(@NotNull Project project, @NotNull String html) {
81+
public static Collection<ProfilerRequestInterface> createRequestsFromIndexHtml(@NotNull Project project, @NotNull String html) {
7182
HtmlFileImpl htmlFile = (HtmlFileImpl) PsiFileFactory.getInstance(project).createFileFromText(HTMLLanguage.INSTANCE, html);
7283

7384
PsiElement[] results = PsiTreeUtil.collectElements(htmlFile, psiElement ->
@@ -83,7 +94,7 @@ public static Collection<ProfilerRequest> createRequestsFromIndexHtml(@NotNull P
8394
return Collections.emptyList();
8495
}
8596

86-
Collection<ProfilerRequest> requests = new ArrayList<>();
97+
Collection<ProfilerRequestInterface> requests = new ArrayList<>();
8798
for (XmlTag tr : tbody.findSubTags("tr")) {
8899
List<String> values = new ArrayList<>();
89100
for (XmlTag td : tr.findSubTags("td")) {
@@ -95,13 +106,42 @@ public static Collection<ProfilerRequest> createRequestsFromIndexHtml(@NotNull P
95106
}
96107

97108
requests.add(
98-
new ProfilerRequest(new String[] {values.get(5), "", values.get(2), values.get(3), values.get(4)}, new ProfilerIndex(new File("aa")))
109+
new HttpProfilerRequest(project, values.get(5), null, values.get(2), values.get(3), values.get(4))
99110
);
100111
}
101112

102113
return requests;
103114
}
104115

116+
@NotNull
117+
public static Collection<ProfilerRequestInterface> collectHttpDataForRequest(@NotNull Project project, @NotNull Collection<ProfilerRequestInterface> requests) {
118+
ExecutorService executor = Executors.newFixedThreadPool(10);
119+
120+
Collection<ProfilerRequestInterface> requestsDecorated = new ArrayList<>();
121+
122+
Collection<Callable<ProfilerRequestInterface>> callable = requests.stream().map(
123+
request -> new MyProfilerRequestDecoratedCollectorCallable(project, request)).collect(Collectors.toCollection(ArrayList::new)
124+
);
125+
126+
List<Future<ProfilerRequestInterface>> futures;
127+
try {
128+
futures = executor.invokeAll(callable);
129+
} catch (InterruptedException e) {
130+
return requests;
131+
}
132+
133+
for (Future<ProfilerRequestInterface> future : futures) {
134+
try {
135+
requestsDecorated.add(future.get());
136+
} catch (ExecutionException | InterruptedException ignored) {
137+
}
138+
}
139+
140+
executor.shutdown();
141+
142+
return requestsDecorated;
143+
}
144+
105145
/**
106146
* "_controller" and "_route"
107147
* "/_profiler/242e61?panel=request"
@@ -227,4 +267,56 @@ private static String stripHtmlTags(@NotNull String text)
227267
{
228268
return text.replaceAll("<[^>]*>", "");
229269
}
270+
271+
@Nullable
272+
public static String getProfilerUrlContent(@NotNull String url) {
273+
System.out.println(url);
274+
URLConnection conn;
275+
try {
276+
conn = new URL(url).openConnection();
277+
} catch (IOException e) {
278+
e.printStackTrace();
279+
return null;
280+
}
281+
282+
try {
283+
try (BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8))) {
284+
return reader.lines().collect(Collectors.joining("\n"));
285+
}
286+
} catch (IOException e) {
287+
e.printStackTrace();
288+
return null;
289+
}
290+
}
291+
292+
private static class MyProfilerRequestDecoratedCollectorCallable implements Callable<ProfilerRequestInterface> {
293+
private final Project project;
294+
private final ProfilerRequestInterface request;
295+
296+
MyProfilerRequestDecoratedCollectorCallable(@NotNull Project project, @NotNull ProfilerRequestInterface request) {
297+
this.project = project;
298+
this.request = request;
299+
}
300+
301+
@Override
302+
public ProfilerRequestInterface call() throws Exception {
303+
Map<String, String> requestAttributes = new HashMap<>();
304+
String url = "http://127.0.0.1:8000/_profiler/" + request.getHash() + "?panel=request";
305+
306+
String contents = REQUEST_CACHE.getIfPresent(url);
307+
if(contents == null) {
308+
contents = ProfilerUtil.getProfilerUrlContent(url);
309+
REQUEST_CACHE.put(url, contents);
310+
}
311+
312+
if(contents != null) {
313+
String finalContents = contents;
314+
ApplicationManager.getApplication().runReadAction(() -> {
315+
requestAttributes.putAll(ProfilerUtil.getRequestAttributes(project, finalContents));
316+
});
317+
}
318+
319+
return new HttpCollectorProfilerRequest(request, new HttpDefaultDataCollector(requestAttributes));
320+
}
321+
}
230322
}

0 commit comments

Comments
 (0)