Centos6.6上rsyslog一些用法和擴展

    友情提醒:本文系統環境vmware 10+Centos 6.6 x86_64,以下涉及到的命令和用法請謹慎使用。

       內容概括:

                (1)rsyslog的配置文件與日誌內容結構解讀

                (2)使用rsyslog做一臺日誌服務器

                (3)rsyslog日誌文件的輪替

                (4)rsyslog與mysql結合將日誌信息寫入數據庫並使用loganalyzer進行管理

    日誌對於系統的重要性不言而喻,比如對於故障診斷和***檢測,沒有日誌幾乎寸步難行。吐槽一下:微軟你妹的,就不能把日誌做的能讓人看明白些,全是錯誤代碼,去你官網查代碼含義得到的也是讓人費解。在此表揚一下Centos 6.6上使用的日誌系統,記錄的日誌清晰明瞭,簡單易讀。收起噁心微軟的心態,隨我去看下centos6.6上的rsyslog 日誌系統吧。

    一.rsyslog的配置文件與日誌內容結構

    rsyslog是Centos6.6上用於記錄應用程序產生日誌的工具,當然應用程序自帶日誌記錄工具的話就不使用rsyslog,比如httpd。rsyslog的官網是: http://www.rsyslog.com 

    在Centos 6.6 x86_64 上由rpm包:rsyslog-5.8.10-8.el6.x86_64.rpm 安裝提供。

   ----------------------------------------------------

    /etc/rc.d/init.d/rsyslog 爲rsyslog程序的啓動管理腳本。

    /etc/sysconfig/rsyslog 爲向rsyslog程序傳遞的參數文件。

    /etc/rsyslog.conf 是rsyslog的主配置文件。
    /etc/rsyslog.d 是rsyslog的輔助配置文件目錄,以Centos特性,當配置項與主配置文件產生衝突時,以該輔助配置文件中的配置項信息爲準。

    /sbin/rsyslogd 是二進制主程序。

    /lib64/rsyslog/*.so是rsyslog的模塊文件。

    /usr/share/doc/rsyslog-5.8.10/ 是文檔文件目錄

    /usr/share/man/man5/rsyslog.conf.5.gz 是rsyslog主配置文件的man手冊
    /usr/share/man/man8/rsyslogd.8.gz 是rsyslog 二進制主程序rsyslogd的man手冊

    /var/log/ 是放置rsyslog記錄的日誌文件的位置。

    --------------------------------------------------

    rsyslog的主配置文件/etc/rsyslog.conf的結構和內容:

    默認情況下主配置文件/etc/rsyslog.conf由3部分組成:

    1) #### MODULES ####  --->啓動/sbin/rsyslogd要加載的模塊

        格式:

               $ModLoad module-name #註釋

         $ModLoad 是關鍵字(/sbin/rsyslogd程序中定義的變量名)

         module-name:出現在/lib64/rsyslog/ 中的模塊名稱,記住不帶.so

 

    2)  #### GLOBAL DIRECTIVES #### ----->全局規則設定

         格式:

               #註釋

               規則內容

          例如:

             # Include all config files in /etc/rsyslog.d/
             $IncludeConfig /etc/rsyslog.d/*.conf

             含義爲啓動時要讀取/etc/rsyslog.d/中所有以.conf爲結尾的文件

    3) #### RULES #### ----->明細程序日誌記錄設定

       格式:

           #註釋

           facility.priority         target

       

        facility:可理解爲“產生日誌對象”,例如:authpriv 是登陸認證的,mail 是郵件系統的。

       

        priority:指定的是日誌級別,centos使用的日誌級別如下,由低到高爲:

            debug
            info
            notice
            warn, warning
            err, error
            crit
            alert
            emerg, panic

            級別越低產生的日誌越明細越多,級別越高產生的日誌越危險越少。

            指定級別的方式:
                *: 所有級別
                none: 沒有級別,就是不記錄的意思
                priority: 比此級別低的(包含該級別的)所有日誌信息都會記錄
                =priority: 僅記錄指定級別


        target:將日誌記錄於指定的目標地點,可以有:

             系統文件中,例如:/var/log/secure

             用戶:將日誌信息通知給用戶。

                  例如:系統默認emerg等級的日誌就顯示給系統上登陸用戶:

                   # Everybody gets emergency messages
                   *.emerg                                                 *

             日誌服務器:使用 @SERVER_ADDRESS 定義日誌服務器地址

             管道:通過管道傳遞給某些命令。 | COMMAND

             在target前使用“-”表示異步寫入。

      

        舉例:

*.info;mail.none;authpriv.none;cron.none                /var/log/messages

含義:系統上所有程序(不包括mail,authprive,cron這些程序)產生的,info等級還有比info等級低的debug等級的日誌信息記錄在/var/log/messages中。

     ------------------------------------------------------

    日誌內容:以/var/log/secure中一條目爲例

    May  9 07:52:33 Test01 sshd[1882]: Accepted password for root from 192.168.100.100 port 49818 ssh2

    May  9 07:52:33:日誌條目產生的時間

    Test01:日誌條目產生的主機(產生事件的地點)

    sshd[1882]:產生日誌條目的程序和進程號(產生日誌的人物)

    Accepted password for root from 192.168.100.100 port 49818 ssh2:日誌內容(產生的時間事件)

     時間,地點,人物,事件--》這不就是中小學學的記敘文四要素嘛!!!


  二.使用rsyslog做一臺日誌服務器

    實驗拓撲:

wKiom1VNeefTwhOfAAE7qsQyz0M589.jpg


    實驗角色設定:

主機
IP地址
角色
Test01
192.168.100.1/24
日誌服務器,接收局域網服務器產生的日誌
Test02
192.168.100.2/24
日誌產生主機,將產生的登陸認證日誌通過局域網傳遞給日誌服務器記錄。

    實驗過程:

日誌產生主機Test02上的配置:

    2.1)設定selinux狀態和iptables防火牆

#測試網絡連通性
[root@Test02 ~]# ping -c 1 192.168.100.1
PING 192.168.100.1 (192.168.100.1) 56(84) bytes of data.
64 bytes from 192.168.100.1: icmp_seq=1 ttl=64 time=3.75 ms
--- 192.168.100.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 4ms
rtt min/avg/max/mdev = 3.759/3.759/3.759/0.000 ms

#設定selinux狀態爲Permissive
[root@Test02 ~]# setenforce 0

#設定防火牆
[root@Test02 ~]# iptables -L -n
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           state RELATED,ESTABLISHED 
ACCEPT     icmp --  0.0.0.0/0            0.0.0.0/0           
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0           state NEW tcp dpt:22 
REJECT     all  --  0.0.0.0/0            0.0.0.0/0           reject-with icmp-host-prohibited 
Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         
REJECT     all  --  0.0.0.0/0            0.0.0.0/0           reject-with icmp-host-prohibited 
Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         
[root@Test02 ~]#


    2.2)修改rsyslog的配置文件,將登陸認證日誌發向Test01

[root@Test02 ~]# vim /etc/rsyslog.conf 
修改:
# The authpriv file has restricted access.
authpriv.*                                              /var/log/secure
authpriv.*                                              @192.168.100.1   
:wq

    2.3)重啓rsyslog進程

[root@Test02 ~]# service rsyslog  restart
Shutting down system logger:                               [  OK  ]
Starting system logger:                                    [  OK  ]
[root@Test02 ~]#


日誌服務器Test01上的配置:

    2.4)修改rsyslog配置文件啓用UDP514端口

[root@Test01 ~]# vim /etc/rsyslog.conf 
# Provides UDP syslog reception
$ModLoad imudp$UDPServerRun 514
:wq

    2.5)重啓rsyslog進程並觀察端口

[root@Test01 ~]# service rsyslog restart
Shutting down system logger:                               [  OK  ]
Starting system logger:                                    [  OK  ]
[root@Test01 ~]# 
[root@Test01 ~]# ss -uapn | grep --color 514
UNCONN     0      0                         *:514                      *:*      users:(("rsyslogd",3509,3))
UNCONN     0      0                        :::514                     :::*      users:(("rsyslogd",3509,4))
[root@Test01 ~]#

    2.6)設定防護牆和selinux

[root@Test01 ~]# setenforce 0
[root@Test01 ~]# iptables -IINPUT 2 -p udp -s 192.168.100.0/24 -d 192.168.100.1 --dport 514 -j ACCEPT
[root@Test01 ~]# iptables -L -n
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           state RELATED,ESTABLISHED 
ACCEPT     udp  --  192.168.0.0/24       192.168.100.1       udp dpt:514 
ACCEPT     icmp --  0.0.0.0/0            0.0.0.0/0           
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0           state NEW tcp dpt:22 
REJECT     all  --  0.0.0.0/0            0.0.0.0/0           reject-with icmp-host-prohibited 
Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         
REJECT     all  --  0.0.0.0/0            0.0.0.0/0           reject-with icmp-host-prohibited 
Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         
[root@Test01 ~]#

    2.7)在Test02上用戶登錄觀察Test01種/var/log/secure文件是否有關於Test02上登陸信息寫入

wKiom1VNqeGTzJGoAAbDmvWI8DM675.jpg


    三. rsyslog的日誌文件的輪替

   

系統的日誌文件會隨着使用天數和發生事件的增加在自動增長,對於7*24*365運行的服務器來說,如果沒有一種機制限制這種增長,那麼會有大部分的硬盤被消耗掉,linux系統設計了一種方式來解決這個問題:日誌輪替。

 日誌輪替就是使用一個程序名爲/usr/sbin/logrotate程序根據配置文件的設定,使用同名的空的日誌文件替換現有的日誌文件,被替換掉的日誌文件,被改名後放置或刪除掉


日誌文件輪替示意圖:

wKioL1VNsW2jY2sZAAY6PMlK6i4043.jpg


    /usr/sbin/logrotate使用的配置文件有2類:

主配置文件/etc/logrotate.conf

輔助配置文件/etc/logrotate.d/*

     *相同配置選項,輔助配置文件中的設定優先被使用。

     logrotate是依靠cron任務實現日誌輪替執行的:

[root@Test01 logrotate.d]# rpm -qf /usr/sbin/logrotate
logrotate-3.7.8-17.el6.x86_64
[root@Test01 logrotate.d]# rpm -ql logrotate
/etc/cron.daily/logrotate  ----------------》看到了該程序安裝後在cron.daily下建立的任務
/etc/logrotate.conf
/etc/logrotate.d
/usr/sbin/logrotate
/usr/share/doc/logrotate-3.7.8
/usr/share/doc/logrotate-3.7.8/CHANGES
/usr/share/doc/logrotate-3.7.8/COPYING
/usr/share/man/man5/logrotate.conf.5.gz
/usr/share/man/man8/logrotate.8.gz
/var/lib/logrotate.status
[root@Test01 logrotate.d]#

   

主配置文件/etc/logrotate.conf中設定:

[root@Test01 ~]# less /etc/logrotate.conf | egrep -v '(^$|^#)'
weekly     ------->設定輪替期限爲每週
rotate 4   ------->輪替後舊的日誌文件保留4個週期
create     ------->創建新的空白文件
dateext    ------->使用時間做爲輪替後文件的後綴
include /etc/logrotate.d  ----->程序啓動同時讀取該目錄下文件的內容爲輪替配置文件
/var/log/wtmp {           ----->針對/var/log/wtmp的做的設定
monthly                   ----->輪替週期爲每月
create 0664 root utmp     ----->創建新的空白文件,權限爲0664,屬主root 屬組utmp
minsize 1M                ----->當日志文件達到1M時,也可觸發輪替
rotate 1                  ----->每次輪替後只保留1箇舊文檔
}
/var/log/btmp {           ----->針對/var/log/btmp做的設定
missingok                 ----->在做輪替時發生數據丟失也沒問題 
monthly    
create 0600 root utmp    
rotate 1
}
[root@Test01 ~]#

輔助配置文件:/etc/logrotate.d/*

[root@Test01 ~]# cd /etc/logrotate.d
[root@Test01 logrotate.d]# ls     ---->可以看到該目錄下文件的命名沒有什麼特殊要求
cups  dracut  httpd  mcelog  mysqld  numad  psacct  samba  syslog  vsftpd  yum
[root@Test01 logrotate.d]# less httpd
/var/log/httpd/*log {  ---->指明要被輪替的文件的位置
    missingok
    notifempty    --------->如果是空文件的話,不轉儲
    sharedscripts --------->該輪替動作只做一次,不管/var/log/httpd/*log能匹配多少日誌文件
    delaycompress --------->轉儲的日誌文件到下一次轉儲時才壓縮
    postrotate    --------->在轉儲以後需要執行的命令可以放入這個對,這兩個關鍵字必須單獨成行
        /sbin/service httpd reload > /dev/null 2>/dev/null || true --->重新加載httpd配置文件
    endscript     --------->關鍵字,表示指明命令結束 
}

*更多logrotate的配置參數參見:# man 8 logrotate   


  從輔助配置文件中可以看到,其實設定日誌文件輪替很容易:

    1)在/var/logrotate.d/ 下建立文件

    2)在1)建立的文件中指明要輪替的日誌文件的位置和輪替參數

    3)讓/usr/sbin/logrotate重新加載配置文件即可


小實驗:手動實現日誌文件的輪替

    1)建立輪替日誌文件:/var/log/test.log

[root@Test01 ~]# touch /var/log/test.log
[root@Test01 ~]# cat /etc/inittab >>/var/log/test.log

    2)在/etc/logrotate.d/下建立指導/var/log/test.log輪替的指導文件test

[root@Test01 ~]# touch /etc/logrotate.d/test
[root@Test01 ~]# vim /etc/logrotate.d/test
/var/log/test.log {
    weekly
     minsize 3M
    create
    rotate 3
    compress
    sharedscripts
    postrotate
       /usr/bin/killall -HUP rsyslogd
    endscript
}

    3)使用logrotate命令手動觸發輪替:

 # logrotate  [-vf]  logfile

 -v:顯示過程

 -f:強制執行輪替,不管是否到達輪替條件。

 Logfile:一般都是 /etc/logrotate.conf

[root@Test01 ~]# ls /var/log
anaconda.ifcfg.log    anaconda.syslog   boot.log    cups        httpd    messages    sa       tallylog  yum.log
anaconda.log          anaconda.xlog     btmp        dmesg       lastlog  mysqld.log  samba    test.log
anaconda.program.log  anaconda.yum.log  ConsoleKit  dmesg.old   maillog  ntpstats    secure   wtmp
anaconda.storage.log  audit             cron        dracut.log  mcelog   prelink     spooler  xferlog
[root@Test01 ~]# logrotate -vf /etc/logrotate.conf 
。。。。。。。。。。
[root@Test01 ~]# ls /var/log/
anaconda.ifcfg.log    boot.log       dmesg.old            messages           secure-20150509       xferlog
anaconda.log          btmp           dracut.log           messages-20150509  spooler               xferlog-20150509
anaconda.program.log  btmp-20150509  dracut.log-20150509  mysqld.log         spooler-20150509      yum.log
anaconda.storage.log  ConsoleKit     httpd                ntpstats           tallylog              yum.log-20150509
anaconda.syslog       cron           lastlog              prelink            test.log
anaconda.xlog         cron-20150509  maillog              sa                 test.log-20150509.gz
anaconda.yum.log      cups           maillog-20150509     samba              wtmp
audit                 dmesg          mcelog               secure             wtmp-20150509
[root@Test01 ~]# vim /etc/logrotate.d/test 
[root@Test01 ~]# ll /var/log/test*
-rw-r--r--. 1 root root   0 May  9 15:47 /var/log/test.log
-rw-r--r--. 1 root root 484 May  9 15:47 /var/log/test.log-20150509.gz
#看到了吧這就是輪替後的被壓縮的文件


    四.rsyslog同mariadb數據庫結合,實現將日誌條目存儲於數據庫

    實驗拓撲:

wKiom1VNv5vT55QBAAJZzvE63EA815.jpg

     實驗角色設定:

主機
IP地址
角色
Test01
192.168.100.1
日誌服務器,收集局域網認證登陸信息放入數據庫中。
提供loganalyzer日誌展示工具
Test02
192.168.100.2
日誌產生服務器,將登陸認證信息記錄至局域網日誌服務器中


     實驗過程:

日誌產生主機Test02上的配置:

    4.1)設定selinux狀態和iptables防火牆

#測試網絡連通性
[root@Test02 ~]# ping -c 1 192.168.100.1
PING 192.168.100.1 (192.168.100.1) 56(84) bytes of data.
64 bytes from 192.168.100.1: icmp_seq=1 ttl=64 time=3.75 ms
--- 192.168.100.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 4ms
rtt min/avg/max/mdev = 3.759/3.759/3.759/0.000 ms

#設定selinux狀態爲Permissive
[root@Test02 ~]# setenforce 0

#設定防火牆
[root@Test02 ~]# iptables -L -n
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           state RELATED,ESTABLISHED 
ACCEPT     icmp --  0.0.0.0/0            0.0.0.0/0           
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0           state NEW tcp dpt:22 
REJECT     all  --  0.0.0.0/0            0.0.0.0/0           reject-with icmp-host-prohibited 
Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         
REJECT     all  --  0.0.0.0/0            0.0.0.0/0           reject-with icmp-host-prohibited 
Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         
[root@Test02 ~]#


    4.2)修改rsyslog的配置文件,將登陸認證日誌發向Test01

[root@Test02 ~]# vim /etc/rsyslog.conf 
修改:
# The authpriv file has restricted access.
authpriv.*                                              /var/log/secure
authpriv.*                                              @192.168.100.1   
:wq

   4.3)重啓rsyslog進程

[root@Test02 ~]# service rsyslog  restart
Shutting down system logger:                               [  OK  ]
Starting system logger:                                    [  OK  ]
[root@Test02 ~]#


日誌服務器Test01上的配置:

     4.4)配置和啓用mysql數據庫

[root@Test01 local]# setenforce 0
[root@Test01 local]# service iptables stop

[root@Test01 local]# service mysqld start
Starting MySQL                                             [  OK  ]
[root@Test01 local]# ss -tlpn | grep --color 3306
LISTEN     0      50                        *:3306                     *:*      users:(("mysqld",1630,15))
[root@Test01 local]#

    4.5)安裝rsyslog同maraidb連接的模塊

[root@Test01 local]# yum -y install rsyslog-mysql
#這個模塊程序包系統光盤上自帶的有
[root@Test01 local]# rpm -ql rsyslog-mysql
/lib64/rsyslog/ommysql.so      ---->生成的模塊
/usr/share/doc/rsyslog-mysql-5.8.10
/usr/share/doc/rsyslog-mysql-5.8.10/createDB.sql  --->自帶的生成rsyslog需要庫表的工具
[root@Test01 local]#

   

    4.6)創建rsyslog在mysql中依賴的庫和用戶

[root@Test01 local]# mysql < /usr/share/doc/rsyslog-mysql-5.8.10/createDB.sql
#這裏mysql登陸用戶使用的root因爲沒設定登陸密碼,故命令這樣使用。

[root@Test01 local]# mysql 
[root@Test01 yum.repos.d]# mysql
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 4
Server version: 5.1.73 Source distribution
Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| Syslog  -----------|-- >多了個Syslog庫 
| mysql              |
| performance_schema |
| test               |
| vsftpd             |
+--------------------+
mysql> GRANT ALL ON Syslog.* TO 'lijun'@'127.0.0.1' IDENTIFIED BY 'redhat';
Query OK, 0 rows affected (0.09 sec)
#添加用戶lijun用於rsyslog聯繫數據庫

mysql> GRANT ALL ON Syslog.* TO 'lijun'@'localhost' IDENTIFIED BY 'redhat';
Query OK, 0 rows affected (0.00 sec)
#添加用戶lijun用於rsyslog聯繫數據庫

mysql> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.00 sec)

    4.7)配置rsyslog的主配置啓用udp514端口和ommysql.so模塊

[root@Test01 local]# vim /etc/rsyslog.conf
#### MODULES ####
$ModLoad imuxsock # provides support for local system logging (e.g. via logger command)
$ModLoad imklog   # provides kernel logging support (previously done by rklogd)
#$ModLoad immark  # provides --MARK-- message capability
$ModLoad ommysql  #啓用4.5)種生成的ommysql模塊
# Provides UDP syslog reception
$ModLoad imudp
$UDPServerRun 514

#啓用udp514用於監聽客戶端日誌寫入

# The authpriv file has restricted access.
#authpriv.*                                              /var/log/secure
authpriv.*                                               :ommysql:127.0.0.1,Syslog,lijun,redhat

#定義將關於登陸認證的信息寫入數據庫。  :模塊名:SQLSERVER地址,庫名,用戶名,登陸密碼

[root@Test01 local]# service rsyslog restart
Shutting down system logger:                               [  OK  ]
Starting system logger:                                    [  OK  ]
[root@Test01 local]#   

    4.8)配置LAMP環境,安裝loganalyzer 用於展示maraidb中記錄的日誌信息

配置LAMP系統環境,

[root@Test01 ~]# yum -y install httpd mysql-server mysql php php-mysql php-gd

安裝loganalyzer:

[root@Test01 ~]# cd /var/www/html
[root@Test01 html]# mkdir tool
[root@Test01 html]# cd /root

[root@Test01 ~]# tar -xf loganalyzer-3.6.5.tar.gz
[root@Test01 ~]# cp -r loganalyzer-3.6.5/src/* /var/www/html/tool
[root@Test01 ~]# cp loganalyzer-3.6.5/contrib/* /var/www/html/tool
[root@Test01 ~]# cd /var/www/html/tool/
[root@Test01 tool]# chmod +x configure.sh secure.sh
[root@Test01 tool]# ./configure.sh

[root@Test01 tool]# chown -R apache.apache ./*

下面使用瀏覽器來安裝吧:

wKioL1VN3d_xF2guAAJlVhXdP4w504.jpg

 wKiom1VN3RfRmyajAAMk2LzpxnQ942.jpg


wKiom1VN3fShyt8LAAQSud4oiFs714.jpg


wKiom1VN3xuh53p0AARuO2B0pg4638.jpg

wKioL1VN5l_CBx1yAAMEh3C7iRg532.jpg



wKioL1VN5V7yIjFAAAg6_Yy6bQs454.jpg

4.9)配置防火牆

[root@Test01 ~]# service iptables  start
[root@Test01 tool]# iptables -IINPUT 2 -p udp -s 192.168.100.0/24 -d 192.168.100.1 --dport 514 -j ACCEPT
[root@Test01 tool]# iptables -IINPUT 3 -p tcp  -s 192.168.100.100 -d 192.168.100.1 --dport 80 -m state --state NEW  -j ACCEPT
[root@Test01 tool]# iptables -IINPUT 4 -p tcp  -d 192.168.100.1 --dport 80 -m state --state NEW  -j DROP

     好吧,這就是rsyslog上一些東東,有錯誤請指出。一下午又過去了,時間過的太快了!!


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章