[구태진] [pinpoint-web #130] Alarm 기능 추가

1. scheduler 등록
2. CheckFilter 조건 변경 (초과에서 이상으로)
3. AlarmMail에서 제목 추가 ( [PINPOINT] ApplicationName alarm.)


git-svn-id: http://svn.bds.nhncorp.com/pe/hippo-web/trunk@3816 84d0f5b1-2673-498c-a247-62c4ff18d310
This commit is contained in:
koo-taejin
2014-05-08 07:20:22 +00:00
parent 6c63303c31
commit fac8a8aaea
18 changed files with 471 additions and 46 deletions
@@ -30,10 +30,11 @@ public class DefaultAlarmJob implements AlarmJob {
@Override
public boolean execute(AlarmEvent event) {
logger.debug("{} execute. CheckFilterList={}, SendFilterList={}", this.getClass().getSimpleName(), checkFilterList, sendFilterList);
logger.debug("{} {} execute. CheckFilterList={}, SendFilterList={}", application, this.getClass().getSimpleName(), checkFilterList, sendFilterList);
for (AlarmCheckFilter checkFilter : this.checkFilterList) {
boolean isSatisfy = checkFilter.execute(event);
logger.debug("{} filter Satisfy({})", checkFilter.getClass().getSimpleName(), isSatisfy);
if (!isSatisfy) {
return false;
}
@@ -1,11 +1,11 @@
package com.nhn.pinpoint.web.alarm.filter;
public abstract class AlarmCheckCountFilter extends AlarmCheckFilter {
public abstract class AlarmCheckCountFilter extends AlarmCheckFilter {
protected boolean check(long count) {
int threshold = getRule().getThresholdRule();
if (count > threshold) {
if (count >= threshold) {
return true;
} else {
return false;
@@ -22,7 +22,7 @@ public abstract class AlarmCheckFilter implements AlarmFilter {
abstract protected boolean check(AlarmEvent event);
protected AlarmRuleResource getRule() {
public AlarmRuleResource getRule() {
return rule;
}
@@ -4,11 +4,11 @@ package com.nhn.pinpoint.web.alarm.filter;
public abstract class AlarmCheckRatesFilter extends AlarmCheckFilter {
protected boolean check(long count, long totalCount) {
double rates = getRates(count, totalCount);
int rates = getRates(count, totalCount);
int threshold = getRule().getThresholdRule();
if (rates > threshold) {
if (rates >= threshold) {
return true;
} else {
return false;
@@ -8,6 +8,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.nhn.pinpoint.web.alarm.AlarmEvent;
import com.nhn.pinpoint.web.alarm.resource.MailResource;
import com.nhn.pinpoint.web.vo.Application;
import com.nhncorp.lucy.net.call.Fault;
import com.nhncorp.lucy.net.call.Reply;
@@ -16,32 +17,26 @@ import com.nhncorp.lucy.net.invoker.InvocationFuture;
import com.nhncorp.lucy.npc.connector.NpcConnectionFactory;
import com.nhncorp.lucy.npc.connector.NpcHessianConnector;
public class AlarmEmailSendFilter extends AlarmSendFilter {
public class AlarmMailSendFilter extends AlarmSendFilter {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
private static final String ADDR_SEPARATOR = ";";
private final Application application;
private final String owlUrl;
private final String serviceId;
private final String sender;
private final String option;
private final MailResource mailResource;
private final List<String> receiverList;
public AlarmEmailSendFilter(Application application, String owlUrl, String serviceId, String sender, String option, List<String> receiverList) {
public AlarmMailSendFilter(Application application, MailResource mailResource, List<String> receiverList) {
this.application = application;
this.owlUrl = owlUrl;
this.serviceId = serviceId;
this.sender = sender;
this.option = option;
this.mailResource = mailResource;
this.receiverList = receiverList;
}
@Override
protected boolean send(AlarmEvent event) {
NpcConnectionFactory factory = new NpcConnectionFactory();
factory.setBoxDirectoryServiceHostName(owlUrl);
factory.setBoxDirectoryServiceHostName(mailResource.getUrl());
factory.setCharset(Charset.forName("UTF-8"));
factory.setLightWeight(true);
@@ -49,6 +44,7 @@ public class AlarmEmailSendFilter extends AlarmSendFilter {
try {
connector = factory.create();
Object[] params = createSendMailParams();
InvocationFuture future = connector.invoke(null, "send", params);
future.await();
Reply reply = (Reply) future.getReturnValue();
@@ -76,12 +72,12 @@ public class AlarmEmailSendFilter extends AlarmSendFilter {
private Object[] createSendMailParams() {
return new Object[] {
serviceId,
option,
sender, /* 보낸이 */
"", /* 답장 받을 주소 */
joinAddresses(receiverList), /* 받는이 */
application.getName() + " error",
mailResource.getServiceId(),
mailResource.getOption(),
mailResource.getSenderEmailAddress(), /* 보낸이 */
"", /* 답장 받을 주소 */
joinAddresses(receiverList), /* 받는이 */
String.format(mailResource.getSubject(), application.getName()),
application.getName() + " error"
};
}
@@ -15,6 +15,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.nhn.pinpoint.web.alarm.AlarmEvent;
import com.nhn.pinpoint.web.alarm.resource.SmsResource;
import com.nhn.pinpoint.web.vo.Application;
/**
@@ -28,17 +29,12 @@ public class AlarmSmsSendFilter extends AlarmSendFilter {
private static final String QUOTATATION = "\"";
private final Application application;
private final String mexMtUrl;
private final String serviceId;
private final String sender;
private final SmsResource smsResource;
private final List<String> receiverList;
public AlarmSmsSendFilter(Application application, String mexMtUrl, String serviceId, String sender, List<String> receiverList) {
public AlarmSmsSendFilter(Application application, SmsResource smsResource, List<String> receiverList) {
this.application = application;
this.mexMtUrl = mexMtUrl;
this.serviceId = serviceId;
this.sender = sender;
this.smsResource = smsResource;
this.receiverList = receiverList;
}
@@ -47,12 +43,12 @@ public class AlarmSmsSendFilter extends AlarmSendFilter {
DefaultHttpClient client = new DefaultHttpClient();
List<NameValuePair> nvps = new ArrayList<NameValuePair>();
nvps.add(new BasicNameValuePair("serviceId", serviceId));
nvps.add(new BasicNameValuePair("sendMdn", QUOTATATION + sender + QUOTATATION));
nvps.add(new BasicNameValuePair("serviceId", smsResource.getServiceId()));
nvps.add(new BasicNameValuePair("sendMdn", QUOTATATION + smsResource.getSenderPhoneNumber() + QUOTATATION));
nvps.add(new BasicNameValuePair("receiveMdnList", convertToReceiverFormat(receiverList)));
nvps.add(new BasicNameValuePair("content", QUOTATATION + null + QUOTATATION));
HttpGet get = new HttpGet(mexMtUrl + "?" + URLEncodedUtils.format(nvps, "UTF-8"));
HttpGet get = new HttpGet(smsResource.getUrl() + "?" + URLEncodedUtils.format(nvps, "UTF-8"));
logger.debug("{}", get.getURI());
@@ -51,10 +51,10 @@ public class FailureCountFilter extends AlarmCheckCountFilter {
LinkDataMap linkDataMap = dao.selectCaller(application, range);
for (LinkData linkData : linkDataMap.getLinkDataList()) {
Application toApplication = linkData.getToApplication();
if (toApplication.getServiceType().isTerminal() || toApplication.getServiceType().isUnknown()) {
logger.debug("Application({}) is invalid serviceType. this is skip.", toApplication.getName());
continue;
}
// if (toApplication.getServiceType().isTerminal() || toApplication.getServiceType().isUnknown()) {
// logger.debug("Application({}) is invalid serviceType. this is skip.", toApplication.getName());
// continue;
// }
AgentHistogramList sourceList = linkData.getSourceList();
Collection<AgentHistogram> agentHistogramList = sourceList.getAgentHistogramList();
@@ -46,10 +46,10 @@ public class FailureRatesFilter extends AlarmCheckRatesFilter {
LinkDataMap linkDataMap = dao.selectCaller(application, range);
for (LinkData linkData : linkDataMap.getLinkDataList()) {
Application toApplication = linkData.getToApplication();
if (toApplication.getServiceType().isTerminal() || toApplication.getServiceType().isUnknown()) {
logger.debug("Application({}) is invalid serviceType. this is skip.", toApplication.getName());
continue;
}
// if (toApplication.getServiceType().isTerminal() || toApplication.getServiceType().isUnknown()) {
// logger.debug("Application({}) is invalid serviceType. this is skip.", toApplication.getName());
// continue;
// }
AgentHistogramList sourceList = linkData.getSourceList();
Collection<AgentHistogram> agentHistogramList = sourceList.getAgentHistogramList();
@@ -66,16 +66,18 @@ public class FailureRatesFilter extends AlarmCheckRatesFilter {
private boolean checkRates(Application toApplication, Collection<AgentHistogram> agentHistogramList) {
long totalCount = 0;
long successCount = 0;
long slowCount = 0;
long errorCount = 0;
for (AgentHistogram agent : agentHistogramList) {
for (TimeHistogram time : agent.getTimeHistogram()) {
totalCount += time.getTotalCount();
successCount += time.getSuccessCount();
slowCount += time.getSlowCount();
errorCount = time.getErrorCount();
}
}
logger.info("{} -> {} {}/{}(error={})", application.getName(), toApplication.getName(), successCount, totalCount, errorCount);
logger.info("{} -> {} {}/{}(slow={}, error={})", application.getName(), toApplication.getName(), successCount, totalCount, slowCount, errorCount);
return check(errorCount, totalCount);
}
@@ -0,0 +1,17 @@
package com.nhn.pinpoint.web.alarm.resource;
public interface MailResource {
String getPinpointUrl();
String getUrl();
String getServiceId();
String getSenderEmailAddress();
String getOption();
String getSubject();
}
@@ -0,0 +1,80 @@
package com.nhn.pinpoint.web.alarm.resource;
import org.springframework.beans.factory.annotation.Value;
/**
*
* @author koo.taejin
*/
public class MailResourceImpl implements MailResource {
@Value("#{dataProps['pinpoint.url']}")
private String pinpointUrl;
@Value("#{dataProps['alarm.mail.url']}")
private String url;
@Value("#{dataProps['alarm.mail.serviceId']}")
private String serviceId;
@Value("#{dataProps['alarm.mail.sender.emailAddress']}")
private String senderEmailAddress;
@Value("#{dataProps['alarm.mail.option']}")
private String option;
@Value("#{dataProps['alarm.mail.subject']}")
private String subject;
@Override
public String getPinpointUrl() {
return pinpointUrl;
}
public void setPinpointUrl(String pinpointUrl) {
this.pinpointUrl = pinpointUrl;
}
@Override
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
@Override
public String getServiceId() {
return serviceId;
}
public void setServiceId(String serviceId) {
this.serviceId = serviceId;
}
@Override
public String getSenderEmailAddress() {
return senderEmailAddress;
}
public void setSenderEmailAddress(String senderEmailAddress) {
this.senderEmailAddress = senderEmailAddress;
}
@Override
public String getOption() {
return option;
}
public void setOption(String option) {
this.option = option;
}
@Override
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
@Override
public String toString() {
return "MailResourceImpl [pinpointUrl=" + pinpointUrl + ", url=" + url + ", serviceId=" + serviceId + ", senderEmailAddress=" + senderEmailAddress
+ ", option=" + option + ", subject=" + subject + "]";
}
}
@@ -0,0 +1,13 @@
package com.nhn.pinpoint.web.alarm.resource;
public interface SmsResource {
String getPinpointUrl();
String getUrl();
String getServiceId();
String getSenderPhoneNumber();
}
@@ -0,0 +1,57 @@
package com.nhn.pinpoint.web.alarm.resource;
import org.springframework.beans.factory.annotation.Value;
/**
*
* @author koo.taejin
*/
public class SmsResourceImpl implements SmsResource {
@Value("#{dataProps['pinpoint.url']}")
private String pinpointUrl;
@Value("#{dataProps['alarm.sms.url']}")
private String url;
@Value("#{dataProps['alarm.sms.serviceId']}")
private String serviceId;
@Value("#{dataProps['alarm.sms.sender.phoneNumber']}")
private String senderPhoneNumber;
@Override
public String getPinpointUrl() {
return pinpointUrl;
}
public void setPinpointUrl(String pinpointUrl) {
this.pinpointUrl = pinpointUrl;
}
@Override
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
@Override
public String getServiceId() {
return serviceId;
}
public void setServiceId(String serviceId) {
this.serviceId = serviceId;
}
@Override
public String getSenderPhoneNumber() {
return senderPhoneNumber;
}
public void setSenderPhoneNumber(String senderPhoneNumber) {
this.senderPhoneNumber = senderPhoneNumber;
}
@Override
public String toString() {
return "SmsResourceImpl [pinpointUrl=" + pinpointUrl + ", url=" + url + ", serviceId=" + serviceId + ", senderPhoneNumber=" + senderPhoneNumber + "]";
}
}
@@ -0,0 +1,10 @@
package com.nhn.pinpoint.web.scheduler;
public interface AlarmScheduler {
void initialize();
void execute();
}
@@ -0,0 +1,218 @@
package com.nhn.pinpoint.web.scheduler;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import com.nhn.pinpoint.web.alarm.AlarmEvent;
import com.nhn.pinpoint.web.alarm.AlarmJob;
import com.nhn.pinpoint.web.alarm.AlarmJobsRepository;
import com.nhn.pinpoint.web.alarm.DefaultAlarmEvent;
import com.nhn.pinpoint.web.alarm.DefaultAlarmJob;
import com.nhn.pinpoint.web.alarm.DefaultAlarmJobsRepository;
import com.nhn.pinpoint.web.alarm.MainCategory;
import com.nhn.pinpoint.web.alarm.SubCategory;
import com.nhn.pinpoint.web.alarm.filter.AlarmCheckFilter;
import com.nhn.pinpoint.web.alarm.filter.AlarmMailSendFilter;
import com.nhn.pinpoint.web.alarm.filter.AlarmSendFilter;
import com.nhn.pinpoint.web.alarm.filter.AlarmSmsSendFilter;
import com.nhn.pinpoint.web.alarm.resource.MailResource;
import com.nhn.pinpoint.web.alarm.resource.SmsResource;
import com.nhn.pinpoint.web.alarm.vo.AlarmContactGroupResource;
import com.nhn.pinpoint.web.alarm.vo.AlarmContactResource;
import com.nhn.pinpoint.web.alarm.vo.AlarmResource;
import com.nhn.pinpoint.web.alarm.vo.AlarmRuleGroupResource;
import com.nhn.pinpoint.web.alarm.vo.AlarmRuleResource;
import com.nhn.pinpoint.web.dao.AlarmResourceDao;
import com.nhn.pinpoint.web.dao.ApplicationIndexDao;
import com.nhn.pinpoint.web.dao.MapStatisticsCallerDao;
import com.nhn.pinpoint.web.vo.Application;
/**
*
* @author koo.taejin
*/
public class DefaultAlarmScheduler implements AlarmScheduler {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
private AlarmJobsRepository repository;
@Autowired
MailResource mailResource;
@Autowired
SmsResource smsResource;
@Autowired
private AlarmResourceDao alarmResourceDao;
@Autowired
private ApplicationIndexDao applicationIndexDao;
@Autowired
private MapStatisticsCallerDao mapStatisticsCallerDao;
@Override
public void initialize() {
logger.info("{} initialize.", this.getClass().getName());
DefaultAlarmJobsRepository repository = new DefaultAlarmJobsRepository();
List<Application> applicationList = applicationIndexDao.selectAllApplicationNames();
List<AlarmResource> alarmResourceList = alarmResourceDao.selectAlarmList();
for (AlarmResource alarmResource : alarmResourceList) {
String agentId = alarmResource.getAgentId();
Application application = findApplication(agentId, applicationList);
if (application == null) {
logger.warn("Can't find Application({}).", agentId);
continue;
}
AlarmJob job = createAlarmJob(application, alarmResource);
if (job == null) {
continue;
}
repository.addAlarmJob(application, job);
}
logger.info("{} initilization success(Registred {} Jobs). ", this.getClass().getName(), repository.getTotalJobCount());
this.repository = repository;
}
@Override
public void execute() {
logger.info("{} execute.", this.getClass().getName());
AlarmEvent event = createAlarmEvent();
int totalJobCount = repository.getTotalJobCount();
List<Application> applicationList = repository.getRegistedApplicationList();
for (Application application : applicationList) {
executeEachApplication(application, event, totalJobCount);
}
}
private Application findApplication(String applicationName, List<Application> applicationList) {
for (Application application : applicationList) {
if (application.getName().equalsIgnoreCase(applicationName)) {
return application;
}
}
return null;
}
private AlarmJob createAlarmJob(Application application, AlarmResource resource) {
DefaultAlarmJob alarmJob = new DefaultAlarmJob(application);
String applicationName = application.getName();
String alarmName = resource.getAlarmGroupName();
AlarmContactGroupResource contactGroup = resource.getAlarmContactGroup();
if (contactGroup == null || CollectionUtils.isEmpty(contactGroup.getAlarmContactList())) {
logger.warn("Application={}, Rule={} does not have contact resource.", applicationName, alarmName);
return null;
}
List<AlarmContactResource> contactResourceList = contactGroup.getAlarmContactList();
List<AlarmSendFilter> alarmSendFilterList = createAlarmSendFilter(application, contactResourceList);
if (CollectionUtils.isEmpty(alarmSendFilterList)) {
logger.warn("Application={}, Rule={} can't find valid contact resource.", applicationName, alarmName);
return null;
}
alarmJob.addFilter(alarmSendFilterList);
AlarmRuleGroupResource ruleGroup = resource.getAlarmRuleGroup();
if (ruleGroup == null || CollectionUtils.isEmpty(ruleGroup.getAlarmRuleList())) {
logger.warn("Application={}, Rule={} does not have rule resource.", applicationName, alarmName);
return null;
}
List<AlarmRuleResource> alarmRuleList = ruleGroup.getAlarmRuleList();
List<AlarmCheckFilter> alarmCheckFilterList = createAlarmCheckFilter(application, alarmRuleList);
alarmJob.addFilter(alarmCheckFilterList);
if (CollectionUtils.isEmpty(alarmCheckFilterList)) {
logger.warn("Application={}, Rule={} can't find valid rule resource.", applicationName, alarmName);
return null;
}
return alarmJob;
}
private List<AlarmSendFilter> createAlarmSendFilter(Application application, List<AlarmContactResource> contactResourceList) {
List<String> phoneNumberList = new ArrayList<String>();
List<String> emailAddressList = new ArrayList<String>();
for (AlarmContactResource contactResource : contactResourceList) {
String phoneNumber = contactResource.getPhoneNum();
if (!StringUtils.isEmpty(phoneNumber)) {
phoneNumberList.add(phoneNumber);
}
String emailAddress = contactResource.getEmailAddress();
if (!StringUtils.isEmpty(emailAddress)) {
emailAddressList.add(emailAddress);
}
}
List<AlarmSendFilter> alarmSendFilter = new ArrayList<AlarmSendFilter>();
if (!CollectionUtils.isEmpty(phoneNumberList)) {
AlarmSendFilter smsSendFilter = new AlarmSmsSendFilter(application, smsResource, phoneNumberList);
alarmSendFilter.add(smsSendFilter);
}
if (!CollectionUtils.isEmpty(emailAddressList)) {
AlarmSendFilter emailSendFilter = new AlarmMailSendFilter(application, mailResource, emailAddressList);
alarmSendFilter.add(emailSendFilter);
}
return alarmSendFilter;
}
private List<AlarmCheckFilter> createAlarmCheckFilter(Application application, List<AlarmRuleResource> ruleResourceList) {
List<AlarmCheckFilter> alarmCheckFilterList = new ArrayList<AlarmCheckFilter>();
for (AlarmRuleResource ruleResource : ruleResourceList) {
MainCategory mainCategory = ruleResource.getMainCategory();
SubCategory subCategory = ruleResource.getSubCategory();
AlarmCheckFilter alarmCheckFilter = subCategory.createAlarmFilter(application, mainCategory, ruleResource);
if (alarmCheckFilter == null) {
logger.warn("{}({}) can't build Filter.", ruleResource.getAlarmRuleName(), ruleResource.getId());
continue;
}
alarmCheckFilterList.add(alarmCheckFilter);
}
return alarmCheckFilterList;
}
private AlarmEvent createAlarmEvent() {
DefaultAlarmEvent event = new DefaultAlarmEvent(System.currentTimeMillis());
event.setMapStatisticsCallerDao(mapStatisticsCallerDao);
return event;
}
private void executeEachApplication(Application application, AlarmEvent event, int totalJobCount) {
List<AlarmJob> jobList = repository.getAlarmJob(application);
AtomicInteger index = new AtomicInteger(1);
for (AlarmJob job : jobList) {
logger.debug("{} ({}/{}) jobs start(TotalJobCount={}).", application.getName(), index.getAndIncrement(), jobList.size(), totalJobCount);
job.execute(event);
}
}
}
+3
View File
@@ -1,11 +1,14 @@
# dev
pinpoint.url=http://dev.pinpoint.nhncorp.com
# mex-mt sms
alarm.sms.url=http://alpha.mobile.nhncorp.com:5001/mex-mt-server/SendBO/sendSMS
alarm.sms.serviceId=EMG00058
alarm.sms.sender.phoneNumber=01086458010
# owl email
alarm.mail.subject=[PINPOINT] %s alarm.
alarm.mail.url=common.mail.mailer.class2.2nd/owl#dev
alarm.mail.serviceId=pinpoint
alarm.mail.option=version=1;mimeCharset=utf-8;debugMode=false
+4 -1
View File
@@ -1,12 +1,15 @@
# local
pinpoint.url=http://dev.pinpoint.nhncorp.com
# mex-mt sms
alarm.sms.url=http://alpha.mobile.nhncorp.com:5001/mex-mt-server/SendBO/sendSMS
alarm.sms.serviceId=EMG00058
alarm.sms.sender.phoneNumber=01086458010
# owl email
alarm.mail.subject=[PINPOINT] %s alarm.
alarm.mail.url=common.mail.mailer.class2.2nd/owl#dev
alarm.mail.serviceId=pinpoint
alarm.mail.option=version=1;mimeCharset=utf-8;debugMode=false
alarm.mail.sender.emailAddress=<dl_labs_p_pinpoint@navercorp.com>
alarm.mail.sender.emailAddress=<dl_labs_p_pinpoint@navercorp.com>
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:task="http://www.springframework.org/schema/task"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-3.0.xsd
">
<description>Spring Batch infrastructure beans.</description>
<bean id="alarmScheduler" class="com.nhn.pinpoint.web.scheduler.DefaultAlarmScheduler" init-method="initialize"/>
<task:scheduler id="batchSchduler" pool-size="2" />
<task:scheduled-tasks scheduler="batchSchduler">
<task:scheduled ref="alarmScheduler" method="execute" fixed-delay="50000" />
</task:scheduled-tasks>
</beans>
+4 -1
View File
@@ -35,7 +35,7 @@
<import resource="classpath:applicationContext-hbase.xml" />
<import resource="classpath:applicationContext-datasource.xml" />
<import resource="classpath:applicationContext-dao-config.xml" />
<!--<import resource="classpath:applicationContext-scheduler.xml" /> -->
<import resource="classpath:applicationContext-scheduler.xml" />
<!--<import resource="classpath:applicationContext-cache.xml" />-->
<bean id="spanMapper" class="com.nhn.pinpoint.web.mapper.SpanMapper"></bean>
@@ -48,4 +48,7 @@
<bean id="rangeFactory" class="com.nhn.pinpoint.web.vo.RangeFactory"></bean>
<bean id="mailResource" class="com.nhn.pinpoint.web.alarm.resource.MailResourceImpl" />
<bean id="smsResource" class="com.nhn.pinpoint.web.alarm.resource.SmsResourceImpl" />
</beans>