Terry.Li-彬

          虛其心,可解天下之問(wèn);專(zhuān)其心,可治天下之學(xué);靜其心,可悟天下之理;恒其心,可成天下之業(yè)。

            BlogJava :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
            143 隨筆 :: 344 文章 :: 130 評(píng)論 :: 0 Trackbacks
          使用定制的 Web Service Appender for Log4j 將日志信息發(fā)送到某一集中位置。Log4j Appender 使您可以在面向服務(wù)架構(gòu) (SOA) 解決方案中調(diào)試和跟蹤任意問(wèn)題。

          引言

          你 可以使用 Web Service Appender 將日志集中到某一位置,同時(shí),Web Service Appender 允許管理者監(jiān)控、開(kāi)發(fā)者調(diào)試面向服務(wù)架構(gòu)(SOA)環(huán)境里可能存在的任何問(wèn)題。Web Service Appender 是一種擴(kuò)展 JAVA 類(lèi),它由 Log4j 的 Appender 類(lèi)擴(kuò)展而來(lái)。

          從定義上看,SOA 是一種彼此可以互相通信的服務(wù)集合,但這些服務(wù)的內(nèi)容是各自獨(dú)立的,每一類(lèi)服務(wù)均不受其它服務(wù)內(nèi)容或服務(wù)狀態(tài)的影響,并且這些服務(wù)都工作在分布式的系統(tǒng)架 構(gòu)里。在 SOA 中,Web 服務(wù)通常被用來(lái)在給定事務(wù)中處理請(qǐng)求,這些請(qǐng)求可以是遺留代碼、企業(yè)級(jí) Java Beans(EJBs) 的封裝,也可以是 Java 類(lèi)的封裝,使用一種可以將日志信息聚集在中心位置里的日志紀(jì)錄方法,能幫助您隔離缺陷和問(wèn)題,并能讓你更好的理解邏輯流的處理。

          將特定模塊或服務(wù)的日志消息紀(jì)錄到一個(gè)中心位置的機(jī)制,可以把可能潛在的問(wèn)題和缺陷降低到最小。

          本文對(duì) Log4j 的功能進(jìn)行了大體的概述,并介紹了如何編寫(xiě)自定義的 Log4j Appender,這類(lèi)特殊的 Appender 將日志消息編到一種特定的 Web 服務(wù)。





          回頁(yè)首


          Log4j 快速入門(mén)

          Log4j 是一種開(kāi)放源代碼的日志庫(kù),它已被發(fā)展為 Apache Software Foundation 日志服務(wù)項(xiàng)目的子項(xiàng)目。該庫(kù)是以 IBM 在 90 年代末開(kāi)發(fā)的日志庫(kù)為基礎(chǔ)的,第一版發(fā)布于 1999 年。現(xiàn)在它在開(kāi)放源代碼團(tuán)體得到了廣泛使用,它的體系是圍繞以下三個(gè)主要概念構(gòu)建起來(lái)的:

          • Logger
          • Appender
          • Layout

          這些概念可以讓您根據(jù)消息類(lèi)型、消息優(yōu)先級(jí)來(lái)紀(jì)錄消息,您可以控制消息在何處結(jié)束及消息如何格式化。 Logger 是應(yīng)用程序首先調(diào)用以初始化消息紀(jì)錄的對(duì)象。當(dāng)把某一消息傳遞給日志時(shí),logger 會(huì)生成 LoggingEvent,對(duì)消息進(jìn)行封裝。之后,Logger 對(duì)象將 LoggingEvent 傳遞給與之關(guān)聯(lián)的 Appender。

          Appender 將 LoggingEvent 所包含的消息發(fā)送給指定的目標(biāo)輸出文件。所謂指定的文件,大多數(shù)情況下,是 Log4 屬性文件。一些 Appender 存在于 Log4j 中。您也可以擴(kuò)展 Appender,使之支持其它的目標(biāo)文件,比如 XML 文件、控制臺(tái)等等。

          在 Log4j 里, LoggingEvent 被賦予某一級(jí)別,以表明它們的優(yōu)先級(jí)。缺省的級(jí)別包括如下幾種:

          • OFF:可能是最高的級(jí)別,它是用來(lái)關(guān)閉日志紀(jì)錄的
          • FATAL:指出現(xiàn)了非常嚴(yán)重的錯(cuò)誤事件,這些錯(cuò)誤可能會(huì)導(dǎo)致應(yīng)用程序異常中止
          • ERROR:指雖有錯(cuò)誤,但仍允許應(yīng)用程序繼續(xù)運(yùn)行
          • WARN:指運(yùn)行環(huán)境潛藏著危害
          • INFO:指報(bào)告信息,這些信息在粗粒度級(jí)別上突出顯示應(yīng)用程序的進(jìn)程
          • DEBUG:指細(xì)粒度信息事件,細(xì)粒度信息事件對(duì)于應(yīng)用程序的調(diào)試是最有用的
          • ALL:可能是最低的級(jí)別,其目的是打開(kāi)所有日志記錄
          Logger 和 Appender 也被賦予上述的某一級(jí)別,并且僅執(zhí)行等于或高于它們自身的級(jí)別的日志請(qǐng)求。比如,如果一個(gè) Appender 屬于 INFO 級(jí)別,而日志請(qǐng)求屬于 DEBUG,那么 Appender 將不會(huì)為給定的日志事件寫(xiě)消息。



          回頁(yè)首


          客戶(hù)端組件

          客戶(hù)端 log4j.properties 文件

          客戶(hù)端 log4j.properties 文件是一種標(biāo)準(zhǔn)文件,它包含服務(wù)或模塊使用的所有 Appender。Web Service Appender 要求有一個(gè)端點(diǎn)(endpoint) 屬性以指定所使用的日志服務(wù)。

          清單 1 描述了使用 WebServiceAppender 所必需的 Web 服務(wù)客戶(hù)端 Log4j 屬性。 黑體顯示的文本指明了將訪問(wèn) WebServiceAppender 服務(wù)器端的 Appender。屬性文件是使用 Log4j 的基本需求,它可以讓您配置應(yīng)用程序以使用多個(gè) Appender 以及 logging severity。一旦應(yīng)用程序進(jìn)入運(yùn)行狀態(tài)或潛在的問(wèn)題得到解決,您就可以輕松地修改屬性文件。


          清單 1:客戶(hù)端 Log4j 的屬性文件

          #set the level of the root logger
          log4j.rootLogger = INFO, CONSOLE
          #set own logger
          log4j.logger.com.carmelouria.logging.test=CONSOLE
          log4j.appender.CONSOLE=com.carmelouria.logging.WebServiceAppender
          log4j.appender.CONSOLE.endpoint=
          http://localhost:9080/log4j/services/LogAppenderService

          log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
          log4j.appender.CONSOLE.layout.ConversionPattern=%p [%t] %c{2} (%M:%L) :: %m%n





          回頁(yè)首


          服務(wù)器的 Log4j.properties 文件

          服 務(wù)器 Log4j.properties 文件被用來(lái)關(guān)聯(lián)客戶(hù)端 Log4j 屬性文件,它指定了日志的級(jí)別及服務(wù)器將如何輸出消息。對(duì)于支持 Log4j 的應(yīng)用程序,您可以定義多個(gè) appender。當(dāng)然,這些 appender 既可以用于客戶(hù)端服務(wù),也可以用于服務(wù)模塊。

          清單 2 描述了一份典型的 Log4j 屬性文件,服務(wù)器端的 WebServiceAppender 使用缺省的 Log4j Appenders。服務(wù)器端的 Appender 可以潛在的調(diào)用另一個(gè) WebServiceAppender,并將日志信息鏈接起來(lái):


          清單 2:服務(wù)器端的 Log4j 屬性文件

          #set the level of the root logger
          log4j.rootLogger = INFO, FILE
          #set own logger
          log4j.appender.FILE=org.apache.log4j.RollingFileAppender
          log4j.appender.FILE.file=c:/temp/log4j/server/server.log
          log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
          log4j.appender.FILE.layout.ConversionPattern=%p [%t] %c{2} (%M:%L) :: %m%n

          客戶(hù)端程序測(cè)試示例:

          這個(gè)客戶(hù)端程序示例是無(wú)格式普通 Java 對(duì)象(POJO),它記錄了一條消息,并被配置為使用 Web Service Appender 來(lái)處理消息。清單 3 顯示了這個(gè)示例:


          清單 3:客戶(hù)端應(yīng)用程序使用 WebServiceAppender 的示例

          package com.carmelouria.logging.test;
          import org.apache.log4j.Level;
          import org.apache.log4j.Logger;
          import org.apache.log4j.PropertyConfigurator;
          /**
          * @author Carmelo Uria
          *
          */
          public class LoggingSample
          {
          private static Logger logger = Logger.getLogger(LoggingSample.class.getName());
          /**
          *
          */
          public LoggingSample()
          {
          super();
          PropertyConfigurator.configure("c:/temp/log4j.properties");
          logger.log(Level.INFO, "LoggingSample instantiation...");
          System.out.println("finished...");
          }
          public static void main(String[] args)
          {
          LoggingSample sample = new LoggingSample();
          }
          }





          回頁(yè)首


          WebServiceAppender

          WebServiceAppender 是必需的,它可以將消息發(fā)送到指定的 Web 服務(wù)。WebServiceAppender 繼承了 org.log4j.Appender,它允許使用 log4.properties,并成為有效的 Log4j Appender。

          WebServiceAppender 使用基于 XML 的遠(yuǎn)程過(guò)程調(diào)用 (JAX-RPC) 的 Java API,來(lái)將消息發(fā)送到服務(wù)器。JAX-RPC 是一種規(guī)范,它描述使用 RPC 和 XML 構(gòu)建 Web 服務(wù)和 Web 服務(wù)客戶(hù)端的應(yīng)用編程接口 (API) 和約定。JAX-RPC 又被稱(chēng)為 JSR 101。

          LoggingEvent 通過(guò) SOAPElement 被分割并表示為 XML。javax.xml.soap.SOAPElement 接口意味著服務(wù)端點(diǎn)接口將包含一個(gè)參數(shù),或返回 javax.xml.soap.SOAPElement 類(lèi)型的值,以對(duì)應(yīng)于 schema 中每個(gè)使用<xsd:any/>的地方。從本質(zhì)上看,它是 XML 參數(shù)的封裝,且沒(méi)有相應(yīng)的序列化/反序列化 JAVA 類(lèi)。例如,一旦客戶(hù)請(qǐng)求記錄一個(gè)消息,就會(huì)創(chuàng)建一個(gè) LoggEvent 對(duì)象,然后傳送給 Appender。在這種情況下,Appender 就是 WebServiceAppender。Appender 檢索事件,并在解析事件中的信息。一些額外的信息會(huì)被加入,如主機(jī)名稱(chēng),這樣您就知道這些消息來(lái)自哪個(gè)系統(tǒng)。同時(shí),append 方法也將消息轉(zhuǎn)換為 SOAPElement,這樣就可以通過(guò) executeWebService 方法將消息傳遞給 Web 服務(wù)。使用 SOAPElement 充分考慮了 WebServiceAppender 未來(lái)版本的可擴(kuò)展性問(wèn)題。


          清單4:執(zhí)行 WebServiceAppender 服務(wù)的 Append 方法

          protected void append(LoggingEvent event)
          {
          // create Web Service client using endpoint
          if (endpoint == null)
          {
          System.out.println("no endpoint set. Check configuration file");
          System.out.println("[" + hostname + "] " + this.layout.format(event));
          return;
          }
          executeWebService(event);
          }
          private void executeWebService(LoggingEvent event)
          {
          SoapClient client = new SoapClient();
          URL endPoint = null;
          try
          {
          endPoint = new URL(getendpoint());
          }
          catch (MalformedURLException e1)
          {
          e1.printStackTrace();
          }
          String nameSpace = "http://ejb.logging.carmelouria.com";
          QName serviceName = new QName(nameSpace, "LogAppenderServiceService");
          QName operation = new QName(nameSpace, "log");
          QName port = new QName(nameSpace, "LogAppenderService");
          Parameter message =
          new Parameter("log", Constants.XSD_ANY, SOAPElement.class, ParameterMode.IN);
          try
          {
          /**
          *create SOAPElement from LoggingEvent need hostname
          */
          Level level = event.getLevel();
          String sysLog = "<syslog>" + new Integer(level.getSyslogEquivalent()).toString()
          + "</syslog>";
          String startTime = new Long(LoggingEvent.getStartTime()).toString();
          String timeTag = "<start_time>" + startTime + "</start_time>";
          String hostName = "<hostname>" + InetAddress.getLocalHost() +
          "</hostname>";
          String threadName = "<thread_name>" + event.getThreadName()
          +"</thread_name>";
          String logger = "<logger>" + event.getLoggerName() + "</logger>";
          String eventMessage = "<message>" + event.getRenderedMessage() +
          "</message>";
          String log = hostName + threadName + logger + timeTag + sysLog +
          eventMessage;
          String throwableInformation[] = event.getThrowableStrRep();
          if (throwableInformation != null)
          {
          for (int i = 0; i < throwableInformation.length; i++)
          {
          String throwable = "<throwable_information>" + throwableInformation[i] +
          "</throwable_information>";
          log += throwable;
          }
          }
          String ndcString = event.getNDC();
          if (throwableInformation != null)
          {
          String throwable = <ndc>" + ndcString + </ndc>";
          log += throwable;
          }
          message.setValue(SOAPElementFactory.create(<log>" + log + </log>"));
          }
          catch (UnknownHostException unknownHostException)
          {
          unknownHostException.printStackTrace();
          }
          catch (SOAPException e2)
          {
          e2.printStackTrace();
          }
          Parameter resultType = newParameter("logResponse",
          Constants.WEBSERVICES_VOID,
          Object.class,
          ParameterMode.OUT);
          Parameter[] parameters = { message };
          try
          {
          // execute client
          Object result =
          client.execute(endPoint, serviceName, operation, "wrapped", null,
          port, resultType, parameters);
          if ((result != null) && (result instanceof String))
          System.out.println((String) result);
          }
          catch (ClientException e)
          {
          e.printStackTrace();
          }
          }

          Hostname

          不幸的是,Log4j 的 LoggingEvent 沒(méi)有包含 Hostname,而 Hostname 是 Web Service Appender 眾多需求之一。在創(chuàng)建 SOAPElement 以前,您可以用下面的語(yǔ)句將 Hostname 添加到 XML 文件里:

          String hostName = "<hostname>" + InetAddress.getLocalHost() + "</hostname>";

          SoapElementFactory

          SoapElementFactory 是主要用于創(chuàng)建 SOAPElement 的類(lèi)。它同時(shí)支持創(chuàng)建 IBM 和 Java 的 SOAPElement 實(shí)現(xiàn),如清單 5 所示:


          清單 5:使用 SoapElementFactory 類(lèi)的創(chuàng)建方法

          public static javax.xml.soap.SOAPElement create(String xml) throws SOAPException
          {
          com.ibm.ws.webservices.engine.xmlsoap.SOAPFactory factory =
          (com.ibm.ws.webservices.engine.xmlsoap.SOAPFactory)
          com.ibm.ws.webservices.engine.xmlsoap.SOAPFactory
          .newInstance();
          SOAPElement element =
          (javax.xml.soap.SOAPElement)factory.createElementFromXMLString(xml);
          return(element);
          }
          public static SOAPElement create(String arg0, String arg1, String arg2,
          boolean ibmSoapElement) throws
          SOAPException
          {
          if (ibmSoapElement)
          {
          SOAPFactory soapFactory =
          (com.ibm.ws.webservices.engine.xmlsoap.SOAPFactory)
          com.ibm.ws.webservices.engine.xmlsoap.SOAPFactory.newInstance();
          return (soapFactory.createSOAPElement(arg0, arg1));
          }
          javax.xml.soap.SOAPFactory soapFactory =
          javax.xml.soap.SOAPFactory.newInstance();
          return (soapFactory.createElement(arg0, arg1, arg2));
          }

          SoapClient

          SoapClient 類(lèi)封裝了 Call 接口的 JAX-RPC 實(shí)現(xiàn),javax.xml.rpc.Call 接口提供了對(duì)服務(wù)端點(diǎn)動(dòng)態(tài)調(diào)用的支持。javax.xml.rpc.Service 接口就好象是創(chuàng)建 Call 實(shí)例的工廠。

          清單 6 說(shuō)明了客戶(hù)端如何動(dòng)態(tài)調(diào)用服務(wù)。這允許對(duì)服務(wù)進(jìn)行變更,而無(wú)需生成客戶(hù)端代理來(lái)訪問(wèn)遠(yuǎn)程服務(wù)。


          清單 6:使用 SoapClient 類(lèi)的調(diào)用方法

          private Object call(SoapService service, QName operation, QName portType,
          String operationStyleProperty,
          String encodingURIProperty, Parameter returnType,
          Parameter[] parameters) throws ClientException
          {
          QName portName;
          String response = null;
          Object results = null;
          Call call = null;
          try
          {
          // check to see if Service object exists
          if (service == null)
          throw new ClientException("Invalid Service object. It maybe null.");
          // retrieve call from Service object
          call = service.createCall();
          call.setOperationName(operation);
          call.setPortTypeName(portType);
          // check call object
          if (call == null)
          throw new ClientException("invalid operation. Call object is null.");
          // set default values
          if (operationStyleProperty == null)
          call.setProperty(Call.OPERATION_STYLE_PROPERTY,
          OPERATION_STYLE_DOCUMENT_TYPE);
          else
          call.setProperty(Call.OPERATION_STYLE_PROPERTY,
          operationStyleProperty);
          if (encodingURIProperty == null)
          call.setProperty(Call.ENCODINGSTYLE_URI_PROPERTY,
          ENCODING_LITERAL);
          else
          call.setProperty(Call.ENCODINGSTYLE_URI_PROPERTY,
          encodingURIProperty);
          call.setTargetEndpointAddress(service.getServiceEndPoint());
          //create Parameter class for SoapClient
          for (int i = 0; i < parameters.length; i++)
          {
          Class classObject = parameters[i].getClassObject();
          if (classObject != null)
          call.addParameter(parameters[i].getName(), parameters[i].getXmlType(),
          parameters[i].getClassObject(), parameters[i].getMode());
          else
          call.addParameter(parameters[i].getName(), parameters[i].getXmlType(),
          parameters[i].getMode());
          }
          // pass parameter as ReturnType
          if (returnType != null)
          {
          if (returnType.getClassObject() != null)
          call.setReturnType(returnType.getXmlType(), returnType.getClassObject());
          else
          call.setReturnType(returnType.getXmlType());
          }
          Object[] request = new Object[parameters.length];
          // add parameter values
          for (int i = 0; i < request.length; i++)
          {
          request[i] = parameters[i].getValue();
          }
          results = call.invoke(request);
          }
          catch (SOAPFaultException e)
          {
          System.out.println(e.getFaultString());
          e.getStackTrace();
          throw new ClientException(e.getLocalizedMessage(), e);
          }
          catch (ServiceException serviceException)
          {
          serviceException.getStackTrace();
          throw new ClientException(serviceException.getLocalizedMessage(),
          serviceException);
          }
          catch (RemoteException exception)
          {
          exception.printStackTrace();
          throw new ClientException(exception.getLocalizedMessage(), exception);
          }
          return (results); }





          回頁(yè)首


          服務(wù)組件

          Log4j.server.properties

          Log4j.server.properties 文件包含了一個(gè)基本的 Log4j 配置文件,該文件可以讓您指定把哪些日志發(fā)送給 Web 服務(wù)系統(tǒng)。


          清單 7:Log4j.server.properties 文件

          #set the level of the root logger
          log4j.rootLogger = INFO, FILE
          #set own logger
          log4j.appender.FILE=org.apache.log4j.RollingFileAppender
          log4j.appender.FILE.file=c:/temp/log4j/server/server.log
          log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
          log4j.appender.FILE.layout.ConversionPattern=%p [%t] %c{2} (%M:%L) :: %m%n

          LogAppenderBean.java

          LogAppenderBean.java 是 Web Service Appender 服務(wù)所要使用的 EJB。該服務(wù)啟動(dòng) LogAppenderBean 以處理來(lái)自每個(gè) Web Service Appender 客戶(hù)端的每一個(gè)請(qǐng)求。

          清單 8 顯示了來(lái)自 WebServiceAppender EJB 的 log 方法,該方法解析來(lái)自客戶(hù)端的消息,并將客戶(hù)端信息紀(jì)錄到服務(wù)的服務(wù)器端。


          清單 8:LogAppenderBean 的 log 方法

          public void log(SOAPElement message)
          {
          try
          {
          InputSource source = ((IBMSOAPElement)
          message).toInputSource(false);
          Document document = Parser.parse(source);
          String log = null;
          String hostname =
          document.selectSingleNode("http://hostname").getText();
          String threadName =
          document.selectSingleNode("http://thread_name").getText();
          String syslog =
          document.selectSingleNode("http://syslog").getText();
          String startTime = new Long(
          document.selectSingleNode("http://start_time").
          getText()).toString();
          log = '[' + startTime + ':' + hostname + ':' + threadName +
          "] " + document.selectSingleNode(
          "http://message").getText();
          // retrieve any throwable messages
          List throwableList = document.selectNodes(
          "http://throwable_information");
          if(throwableList != null)
          {
          Iterator throwables = throwableList.iterator();
          while(throwables.hasNext())
          {
          log += '\n' + ((Node)throwables.next()).getText();
          }

          log += '\n';
          }

          logger.log(Level.toLevel(new Integer(syslog).intValue()),
          log);
          logger.log(Level.INFO,log);
          }
          catch(ParserException parseException)
          {
          parseException.printStackTrace();
          }
          catch (SAXException e)
          {
          e.printStackTrace();
          }
          }

          通過(guò) IBM SOAPElement 的 InputSource,每一個(gè) SOAPElement 的內(nèi)容都會(huì)被檢索。目前,只有 IBM WebSphere? Application Server (Application Server) 支持這些代碼(請(qǐng)參閱參考資料)。 然而,如果您移除 IBM SOAPElement,那么您就可以在任何應(yīng)用服務(wù)器上使用這些代碼。IBM SOAPElement 內(nèi)置的性能優(yōu)化也適用于 Application Server。

          每一個(gè) SOAPElement 都使用 Dom4j 來(lái)讀取、解析和轉(zhuǎn)換。Dom4j 是一種在內(nèi)存中表示 XML 樹(shù)的對(duì)象模型。Dom4j 提供了一組易于使用的 API,從而為我們提供了一整套強(qiáng)大的功能來(lái)處理、操作或定位 XML,使用 XPath 和 XSLT 進(jìn)行工作,以及與 SAX、 JAXP、DOM 集成。

          除了可以使用任意的 XML 解析器外,DOM4J 還允許使用任意的 SAX 解析器,為實(shí)現(xiàn)更好的性能,還允許使用所有標(biāo)準(zhǔn)的 XSLT 轉(zhuǎn)換器。 轉(zhuǎn)換被用來(lái)析取發(fā)送給 Web Service Appender 的客戶(hù)端 LoggingEvent 的元素。

          如果您允許使用 SOAPElement,那么就需要在代碼中維持最大限度的靈活性。Web Service Appender 服務(wù)可以被修改,以支持所有發(fā)送給服務(wù)的 XML。





          回頁(yè)首


          輸出

          下面的示例展示了 Web Service Appender 的可能的輸出:

          INFO [WebContainer : 0] ejb.LogAppenderBean (log:?) :: [1111513482641:OO7-64BIT/9.48.114.183:main]LoggingSample instantiation...

          OO7-64BIT/9.48.114.183 是機(jī)器名和 IP 地址,而 main 是日志所在處的方法名。





          回頁(yè)首


          結(jié)束語(yǔ)

          Web Service Appender 是將日志集中到某一位置的基本工具。由于 Web Service Appender 是 Log4j 的 Appender 類(lèi)的子集,因而配置和使用 Appender 都非常簡(jiǎn)單易懂。您可以修改 Log4j 的屬性文件,這樣,使用 Log4j 的現(xiàn)有應(yīng)用程序和服務(wù)就可以馬上使用 Web Service Appender。






          回頁(yè)首


          下載

          描述名字大小下載方法
          Foundation Class Libraryfoundation.zip47 KBHTTP
          Logging Web Service J2EE ApplicationLoggingWebService.ear1976 KBHTTP
          Unit Test Sample CodeSoapClientTest.java5 KBHTTP
          posted on 2009-07-15 11:49 禮物 閱讀(698) 評(píng)論(0)  編輯  收藏 所屬分類(lèi): web serviceLog
          主站蜘蛛池模板: 开平市| 水城县| 壤塘县| 新余市| 集贤县| 黄浦区| 鄯善县| 东源县| 大埔区| 阿拉善左旗| 衡阳县| 库车县| 蛟河市| 济阳县| 紫金县| 申扎县| 平武县| 万盛区| 南充市| 漳浦县| 武乡县| 牡丹江市| 赤城县| 尖扎县| 巩留县| 枝江市| 瑞昌市| 亚东县| 上栗县| 吐鲁番市| 灵川县| 体育| 新干县| 乌兰察布市| 美姑县| 三都| 井陉县| 荆州市| 靖安县| 湖南省| 汉寿县|