Tuesday, April 6, 2010

Инсталяция Eclipse

Чтобы не забыть, какие я обычно плагины ставлю к Eclipse.

1. Subclipse
http://subclipse.tigris.org/

2. eclipse-hide-toolbar
http://code.google.com/p/eclipse-hide-toolbar/

3. Eclipse WTP

4. Wireframe Sketcher
http://wireframesketcher.com/

5. PyDev (sometimes)
http://pydev.org/

Thursday, August 27, 2009

Java, который я не понимаю

Еще одна, наряду с добавлением элементов из одной типизированной wildcard коллекцией в другую особенность родовых типов в Java.

А именно, параметры для родовых типов не определяются автоматически (infer) из контекста. Хотя определяются автоматически для родовых функций. Поясню на примере. Фрагмент кода 1:
<T> String cat(T a, T b) { return String.valueOf(a) + String.valueOf(b); } ... System.out.println(cat(1, 2));
В этом фрагменте при инстанциировании cat компилятор автоматически определит, что T - int.

Фрагмент кода 2:
class Cat<T> { T a, b; Cat(T a, T b) { this.a = a; this.b = b; } String cat() { return String.valueOf(a) + String.valueOf(b); } } ... System.out.println(new Cat(1, 2).cat());
В этом фрагменте при инстанциировании класса Cat компилятор выдаст предупреждение, что класс родовой класс используется без указания родового параметра. Хотя из вызова конструктора можно было эти родовые параметры определить. Так как компилятор такого не делает, приходится лишний раз руками указывать тип:
System.out.println(new Cat<Integer>(1, 2).cat());
Это, конечно, плохо с точки зрения читабельности и поддерживаемости кода.

В Internet не очень много информации, почему так сделано. Я нашел только одно старое упоминание вот здесь форуме Sun, в котором говориться о том, что автоматическое определение родовых параметров расходится с идеологией Java. Но для методов так же сделано - почему для них не расходиться.

Thursday, June 25, 2009

Мониторинг лог-файлов с использованием Zabbix

Программный комплекс Zabbix (www.zabbix.com) - популярное средство для мониторинга компьютерных систем. Zabbix позволяет отслеживать различные системные и прикладные показатели, например, загруженность CPU и сетевых интерфейсов, скорость работы сайтов, размер пула соединений и др. При возникновении внештатных ситуаций можно настроить уведомление по различным каналам вроде емейл и SMS.

Часто возникает необходимость мониторинга лог-файлов. А именно, при возникновении ошибочной ситуации было бы полезно отсылать письмо или SMS. В версии 1.4 Zabbix нет встроенных средств, которые бы позволяли такое сделать. Мне пришлось для этого написать небольшой скрипт на bash, который потом подключить как пользовательский параметр в Zabbix. Скрипт можно скачать здесь diglog.sh

Для подключения скрипта в Zabbix нужно выполнить следующее:

1. Прописать в zabbix-agentd.conf строку для определения нового пользовательского параметра: UserParameter=diglog[*],/etc/zabbix/alert.d/diglog.sh $1 $2 После чего перезапустить zabbix-agent

2. Через веб-интерфейс Zabbix добавить новый Item. Ключ (key) у него должен быть, например, таким diglog[/home/application/application.log,/tmp/application.log.diglog] Первый параметр - это путь к лог-файлу, который нужно мониторить. Второй параметр - путь к файлу состояния, в котором будет хранится текущее положение в лог-файле. Файл состояния должен быть свой для каждого лог-файла.
Тип у Item'а должен быть Character по крайней мере для Zabbix 1.4.
После добавления Zabbix сразу же начнет выбирать по одной строчки из лог-файла.

3. Добавить триггер для обработку ошибок в лог-файле, например, с таким выражением: {ZABBIX Server:diglog[/home/application/application.log,/tmp/application.logdiglog].str(ERROR)}=1
4. Подключить к триггеру действия для отсылки уведомления об ошибке.

Wednesday, February 4, 2009

Collection.addAll в Java Generics

Родовые типы (generics) в Java - одна из самых интересных и полезных возможностей. Она очень грамотно и логично спроектирована, но иногда попадаются моменты, которые ставят в тупик. Лично я пару натыкался на такой фрагмент:
List<? extends MyType> l1; List<? extends MyType> l2; l1.addAll(l2); Компилятор при этом выдает ошибку в строке, где элементы одной коллекции добавляются в другую. Казалось бы, в чем проблема - коллекции типизированы одинаково, следовательно, могут содержать одинаковые элементы. На самом деле, если бы такой код был допустимым, нарушалась бы безопасность типов (в коллекцию можно было бы добавить недопустимые элементы). Это демонстрирует следующий пример:
List<Double> dl = null; List<Integer> il = null; List<? extends Number> l1 = dl; List<? extends Number> l2 = il; l1.addAll(l2); В коллекцию Double попадают объекты типа Integer.

Thursday, December 11, 2008

Java API для Sape.ru

Выложил в публичный доступ когда-то написанный интерфейс для работы с биржей ссылок SAPE.ru. Описание, а также исходники можно посмотреть на Google Code, адрес такой http://javasape.googlecode.com/. Комментарии можно ссылать по мылу или писать прямо в этом посте.

Thursday, October 23, 2008

Интересный способ мониторинга рабочих сайтов

Иногда возникает ситуация, когда рабочий (production) сайт начинает тормозить, или вообще подвисать. Для нахождения проблемы можно просмотреть код в поисках узких мест или написать нагрузочный тест и посмотреть профилировщиком методы, которые выполняются много времени.

Но часто бывает так, что сайт начинает тормозить только при некотором стечении обстоятельств, например, когда заходит определенный пользователь на определенную страницу. Такого рода узкие места нагрузочным тестом не покроешь, так как не ясно, на каких именно данных проявляется проблема.

В этом случае можно воспользоваться утилитой jstack которая входит в состав JDK начиная с версии 1.5.0. Эта утилита позволяет просмотреть текущее состояние работающих в указанной виртуальной машине потоков (которые thread). Например,
user@laptop$ jstack 3344 "btpool0-439" prio=10 tid=0xa98da000 nid=0x1b3a in Object.wait() [0xa99ff000..0xa99ff130] java.lang.Thread.State: TIMED_WAITING (on object monitor) at java.lang.Object.wait(Native Method) at org.mortbay.thread.BoundedThreadPool$PoolThread.run(BoundedThreadPool.java:482) - locked <0xb47e0078> (a org.mortbay.thread.BoundedThreadPool$PoolThread) "Java2D Disposer" daemon prio=10 tid=0xaa35c800 nid=0xb2e in Object.wait() [0xa9fd4000..0xa9fd50b0] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:116) - locked <0xaf007a30> (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:132) at sun.java2d.Disposer.run(Disposer.java:125) at java.lang.Thread.run(Thread.java:619) Для каждого потока показаны его атрибуты, в том числе его название, и стектрейс.

Идея в том, чтобы на каждом запросе добавлять в название потока информацию, необходимую для идентификации узких мест. Тогда использовав jstack, из названия потока можно посмотреть, над чем в данный момент работает он работает.

Например, очевидными кандидатами на добавление в название потока являются адрес страницы, которая обрабатывается и логин пользователя. Код по добавлению этой информации логично разместить в HTTP-фильтре. Фрагмент его будет выглядеть приблизительно так:
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { String threadName = getUser().login + ": " + RequestInfo.get().getRequestUrl(); Thread.currentThread().setName(threadName); chain.doFilter(request, response); } Теперь, если в выводе jstack будет часто видно, например, такое
"medved: /heavy/calculation" prio=10 tid=0x9aa9a800 nid=0x2519 runnable [0x9ad18000..0x9ad 190b0] java.lang.Thread.State: RUNNABLE at com.site.heavy.calculation.Calc.inner(Calc.java:113) at com.site.heavy.calculation.Calc.outer(Calc.java:43) значит, для пользователя medved медленно показывается страница /heavy/calculation. Это уже можно профилировать.

Названия потока удобно использовать также в других случаях отладки, например, записать в него User-Agent, и тогда прямо в стектрейсе ошибки будет видно, под каким браузером она возникла.

Monday, October 13, 2008

Консерваторы и демократы

(Не удержался, чтобы не перепостить - уж очень понравилось.)

Я спросил несовершеннолетнюю дочь своих друзей, кем бы она хотела быть, когда вырастет. Она сказала, что хотела бы когда-нибудь стать Президентом Соединённых Штатов Америки. Оба счастливых родителя, либеральные демократы, присутствовавшие при разговоре, с гордостью переглянулись. Я спросил девочку: "Хорошо, допустим ты стала Президентом, что бы ты сделала в первую очередь?"

Она ответила: "Первым делом я бы предоставила пищу и жильё всем бездомным".

"Чудесно, - согласился я, - весьма достойная цель! Но вовсе не обязательно ждать того времени, когда ты станешь Президентом. Можно уже сейчас начать действовать в соответствии с твоим планом. Приходи ко мне в дом, выполи сорняки в саду, постриги траву на лужайке, подмети двор, и я заплачу тебе пятьдесят долларов. Тогда ты сможешь пойти к лавке, возле которой валяется один из бездомных, и вручить ему свои $50 на покупку еды или для сбережений в счёт покупки будущего дома".

Она надолго задумалась. Её мать смотрела на меня так выразительно, что я не берусь истолковывать её взгляд. В конце концов девочка подняла глаза и спросила: "Почему бы тогда этому бездомному самому не прийти к вам домой и не сделать эту работу - тогда вы бы прямо ему и заплатили эти 50 долларов?"

Я ответил: "Добро пожаловать в ряды консерваторов, дочка!"

Её родители до сих пор со мной не общаются...

Источник: http://art-of-arts.livejournal.com/