*** a/doc/src/sgml/monitoring.sgml
--- b/doc/src/sgml/monitoring.sgml
***************
*** 270,275 **** postgres: <replaceable>user</> <replaceable>database</> <replaceable>host</> <re
--- 270,283 ----
       </row>
  
       <row>
+       <entry><structname>pg_stat_archiver</><indexterm><primary>pg_stat_archiver</primary></indexterm></entry>
+       <entry>One row only, showing statistics about the
+        WAL archiver process's activity. See
+        <xref linkend="pg-stat-archiver-view"> for details.
+       </entry>
+      </row>
+ 
+      <row>
        <entry><structname>pg_stat_bgwriter</><indexterm><primary>pg_stat_bgwriter</primary></indexterm></entry>
        <entry>One row only, showing statistics about the
         background writer process's activity. See
***************
*** 648,653 **** postgres: <replaceable>user</> <replaceable>database</> <replaceable>host</> <re
--- 656,718 ----
     </para>
    </note>
  
+   <table id="pg-stat-archiver-view" xreflabel="pg_stat_archiver">
+    <title><structname>pg_stat_archiver</structname> View</title>
+ 
+    <tgroup cols="3">
+     <thead>
+      <row>
+       <entry>Column</entry>
+       <entry>Type</entry>
+       <entry>Description</entry>
+      </row>
+     </thead>
+ 
+     <tbody>
+      <row>
+       <entry><structfield>archived_wals</></entry>
+       <entry><type>bigint</type></entry>
+       <entry>Number of WAL files that have been successfully archived</entry>
+      </row>
+      <row>
+       <entry><structfield>last_archived_wal</></entry>
+       <entry><type>text</type></entry>
+       <entry>Name of the last WAL file successfully archived</entry>
+      </row>
+      <row>
+       <entry><structfield>last_archived_wal_time</></entry>
+       <entry><type>timestamp with time zone</type></entry>
+       <entry>Time of the last successful archive operation</entry>
+      </row>
+      <row>
+       <entry><structfield>failed_attempts</></entry>
+       <entry><type>bigint</type></entry>
+       <entry>Number of failed attempts for archiving WAL files</entry>
+      </row>
+      <row>
+       <entry><structfield>last_failed_wal</></entry>
+       <entry><type>text</type></entry>
+       <entry>Name of the WAL file of the last failed archival operation</entry>
+      </row>
+      <row>
+       <entry><structfield>last_failed_wal_time</></entry>
+       <entry><type>timestamp with time zone</type></entry>
+       <entry>Time of the last failed archival operation</entry>
+      </row>
+      <row>
+       <entry><structfield>stats_reset</></entry>
+       <entry><type>timestamp with time zone</type></entry>
+       <entry>Time at which these statistics were last reset</entry>
+      </row>
+     </tbody>
+    </tgroup>
+   </table>
+ 
+   <para>
+    The <structname>pg_stat_archiver</structname> view will always have a
+    single row, containing data about the archiver process of the cluster.
+   </para>
+ 
    <table id="pg-stat-bgwriter-view" xreflabel="pg_stat_bgwriter">
     <title><structname>pg_stat_bgwriter</structname> View</title>
  
***************
*** 1613,1618 **** postgres: <replaceable>user</> <replaceable>database</> <replaceable>host</> <re
--- 1678,1685 ----
         argument (requires superuser privileges).
         Calling <literal>pg_stat_reset_shared('bgwriter')</> will zero all the
         counters shown in the <structname>pg_stat_bgwriter</> view.
+        Calling <literal>pg_stat_reset_shared('archiver')</> will zero all the
+        counters shown in the <structname>pg_stat_archiver</> view.
        </entry>
       </row>
  
*** a/src/backend/catalog/system_views.sql
--- b/src/backend/catalog/system_views.sql
***************
*** 672,677 **** CREATE VIEW pg_stat_xact_user_functions AS
--- 672,688 ----
      WHERE P.prolang != 12  -- fast check to eliminate built-in functions
            AND pg_stat_get_xact_function_calls(P.oid) IS NOT NULL;
  
+ CREATE VIEW pg_stat_archiver AS
+     SELECT
+         s.archived_wals,
+         s.last_archived_wal,
+         s.last_archived_wal_time,
+         s.failed_attempts,
+         s.last_failed_wal,
+         s.last_failed_wal_time,
+         s.stats_reset
+     FROM pg_stat_get_archiver() s;
+ 
  CREATE VIEW pg_stat_bgwriter AS
      SELECT
          pg_stat_get_bgwriter_timed_checkpoints() AS checkpoints_timed,
*** a/src/backend/postmaster/pgarch.c
--- b/src/backend/postmaster/pgarch.c
***************
*** 36,41 ****
--- 36,42 ----
  #include "access/xlog_internal.h"
  #include "libpq/pqsignal.h"
  #include "miscadmin.h"
+ #include "pgstat.h"
  #include "postmaster/fork_process.h"
  #include "postmaster/pgarch.h"
  #include "postmaster/postmaster.h"
***************
*** 496,505 **** pgarch_ArchiverCopyLoop(void)
--- 497,513 ----
  			{
  				/* successful */
  				pgarch_archiveDone(xlog);
+ 
+ 				/* Tell the collector about the WAL file that we successfully archived */
+ 				pgstat_send_archiver(xlog, false);
+ 
  				break;			/* out of inner retry loop */
  			}
  			else
  			{
+ 				/* Tell the collector about the WAL file that we failed to archive */
+ 				pgstat_send_archiver(xlog, true);
+ 
  				if (++failures >= NUM_ARCHIVE_RETRIES)
  				{
  					ereport(WARNING,
*** a/src/backend/postmaster/pgstat.c
--- b/src/backend/postmaster/pgstat.c
***************
*** 221,226 **** static int	localNumBackends = 0;
--- 221,227 ----
   * Contains statistics that are not collected per database
   * or per table.
   */
+ static PgStat_ArchiverStats archiverStats;
  static PgStat_GlobalStats globalStats;
  
  /* Write request info for each database */
***************
*** 292,297 **** static void pgstat_recv_resetsinglecounter(PgStat_MsgResetsinglecounter *msg, in
--- 293,299 ----
  static void pgstat_recv_autovac(PgStat_MsgAutovacStart *msg, int len);
  static void pgstat_recv_vacuum(PgStat_MsgVacuum *msg, int len);
  static void pgstat_recv_analyze(PgStat_MsgAnalyze *msg, int len);
+ static void pgstat_recv_archiver(PgStat_MsgArchiver *msg, int len);
  static void pgstat_recv_bgwriter(PgStat_MsgBgWriter *msg, int len);
  static void pgstat_recv_funcstat(PgStat_MsgFuncstat *msg, int len);
  static void pgstat_recv_funcpurge(PgStat_MsgFuncpurge *msg, int len);
***************
*** 1257,1269 **** pgstat_reset_shared_counters(const char *target)
  				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
  				 errmsg("must be superuser to reset statistics counters")));
  
! 	if (strcmp(target, "bgwriter") == 0)
  		msg.m_resettarget = RESET_BGWRITER;
  	else
  		ereport(ERROR,
  				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
  				 errmsg("unrecognized reset target: \"%s\"", target),
! 				 errhint("Target must be \"bgwriter\".")));
  
  	pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_RESETSHAREDCOUNTER);
  	pgstat_send(&msg, sizeof(msg));
--- 1259,1273 ----
  				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
  				 errmsg("must be superuser to reset statistics counters")));
  
! 	if (strcmp(target, "archiver") == 0)
! 		msg.m_resettarget = RESET_ARCHIVER;
! 	else if (strcmp(target, "bgwriter") == 0)
  		msg.m_resettarget = RESET_BGWRITER;
  	else
  		ereport(ERROR,
  				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
  				 errmsg("unrecognized reset target: \"%s\"", target),
! 				 errhint("Target must be \"archiver\" or \"bgwriter\".")));
  
  	pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_RESETSHAREDCOUNTER);
  	pgstat_send(&msg, sizeof(msg));
***************
*** 2323,2328 **** pgstat_fetch_stat_numbackends(void)
--- 2327,2349 ----
  
  /*
   * ---------
+  * pgstat_fetch_stat_archiver() -
+  *
+  *	Support function for the SQL-callable pgstat* functions. Returns
+  *	a pointer to the archiver statistics struct.
+  * ---------
+  */
+ PgStat_ArchiverStats *
+ pgstat_fetch_stat_archiver(void)
+ {
+ 	backend_read_statsfile();
+ 
+ 	return &archiverStats;
+ }
+ 
+ 
+ /*
+  * ---------
   * pgstat_fetch_global() -
   *
   *	Support function for the SQL-callable pgstat* functions. Returns
***************
*** 3036,3041 **** pgstat_send(void *msg, int len)
--- 3057,3084 ----
  }
  
  /* ----------
+  * pgstat_send_archiver() -
+  *
+  *	Tell the collector about the WAL file that we successfully
+  *	archived or failed to archive.
+  * ----------
+  */
+ void
+ pgstat_send_archiver(const char *xlog, bool failed)
+ {
+ 	PgStat_MsgArchiver	msg;
+ 
+ 	/*
+ 	 * Prepare and send the message
+ 	 */
+ 	pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_ARCHIVER);
+ 	msg.m_failed = failed;
+ 	strncpy(msg.m_xlog, xlog, sizeof(msg.m_xlog));
+ 	msg.m_timestamp = GetCurrentTimestamp();
+ 	pgstat_send(&msg, sizeof(msg));
+ }
+ 
+ /* ----------
   * pgstat_send_bgwriter() -
   *
   *		Send bgwriter statistics to the collector
***************
*** 3278,3283 **** PgstatCollectorMain(int argc, char *argv[])
--- 3321,3330 ----
  					pgstat_recv_analyze((PgStat_MsgAnalyze *) &msg, len);
  					break;
  
+ 				case PGSTAT_MTYPE_ARCHIVER:
+ 					pgstat_recv_archiver((PgStat_MsgArchiver *) &msg, len);
+ 					break;
+ 
  				case PGSTAT_MTYPE_BGWRITER:
  					pgstat_recv_bgwriter((PgStat_MsgBgWriter *) &msg, len);
  					break;
***************
*** 3563,3568 **** pgstat_write_statsfiles(bool permanent, bool allDbs)
--- 3610,3621 ----
  	(void) rc;					/* we'll check for error with ferror */
  
  	/*
+ 	 * Write archiver stats struct
+ 	 */
+ 	rc = fwrite(&archiverStats, sizeof(archiverStats), 1, fpout);
+ 	(void) rc;					/* we'll check for error with ferror */
+ 
+ 	/*
  	 * Walk through the database table.
  	 */
  	hash_seq_init(&hstat, pgStatDBHash);
***************
*** 3828,3843 **** pgstat_read_statsfiles(Oid onlydb, bool permanent, bool deep)
  						 HASH_ELEM | HASH_FUNCTION | HASH_CONTEXT);
  
  	/*
! 	 * Clear out global statistics so they start from zero in case we can't
! 	 * load an existing statsfile.
  	 */
  	memset(&globalStats, 0, sizeof(globalStats));
  
  	/*
  	 * Set the current timestamp (will be kept only in case we can't load an
  	 * existing statsfile).
  	 */
  	globalStats.stat_reset_timestamp = GetCurrentTimestamp();
  
  	/*
  	 * Try to open the stats file. If it doesn't exist, the backends simply
--- 3881,3898 ----
  						 HASH_ELEM | HASH_FUNCTION | HASH_CONTEXT);
  
  	/*
! 	 * Clear out global and archiver statistics so they start from zero
! 	 * in case we can't load an existing statsfile.
  	 */
  	memset(&globalStats, 0, sizeof(globalStats));
+ 	memset(&archiverStats, 0, sizeof(archiverStats));
  
  	/*
  	 * Set the current timestamp (will be kept only in case we can't load an
  	 * existing statsfile).
  	 */
  	globalStats.stat_reset_timestamp = GetCurrentTimestamp();
+ 	archiverStats.stat_reset_timestamp = globalStats.stat_reset_timestamp;
  
  	/*
  	 * Try to open the stats file. If it doesn't exist, the backends simply
***************
*** 3875,3881 **** pgstat_read_statsfiles(Oid onlydb, bool permanent, bool deep)
  	if (fread(&globalStats, 1, sizeof(globalStats), fpin) != sizeof(globalStats))
  	{
  		ereport(pgStatRunningInCollector ? LOG : WARNING,
! 				(errmsg("corrupted statistics file \"%s\"", statfile)));
  		goto done;
  	}
  
--- 3930,3946 ----
  	if (fread(&globalStats, 1, sizeof(globalStats), fpin) != sizeof(globalStats))
  	{
  		ereport(pgStatRunningInCollector ? LOG : WARNING,
! 				(errmsg("corrupted statistics file (global) \"%s\"", statfile)));
! 		goto done;
! 	}
! 
! 	/*
! 	 * Read archiver stats struct
! 	 */
! 	if (fread(&archiverStats, 1, sizeof(archiverStats), fpin) != sizeof(archiverStats))
! 	{
! 		ereport(pgStatRunningInCollector ? LOG : WARNING,
! 				(errmsg("corrupted statistics file (archiver) \"%s\"", statfile)));
  		goto done;
  	}
  
***************
*** 4159,4165 **** done:
   *	stats_timestamp value.
   *
   *	- if there's no db stat entry (e.g. for a new or inactive database),
!  *	there's no stat_timestamp value, but also nothing to write so we return
   *	the timestamp of the global statfile.
   * ----------
   */
--- 4224,4230 ----
   *	stats_timestamp value.
   *
   *	- if there's no db stat entry (e.g. for a new or inactive database),
!  *	there's no stats_timestamp value, but also nothing to write so we return
   *	the timestamp of the global statfile.
   * ----------
   */
***************
*** 4169,4174 **** pgstat_read_db_statsfile_timestamp(Oid databaseid, bool permanent,
--- 4234,4240 ----
  {
  	PgStat_StatDBEntry dbentry;
  	PgStat_GlobalStats myGlobalStats;
+ 	PgStat_ArchiverStats myArchiverStats;
  	FILE	   *fpin;
  	int32		format_id;
  	const char *statfile = permanent ? PGSTAT_STAT_PERMANENT_FILENAME : pgstat_stat_filename;
***************
*** 4211,4216 **** pgstat_read_db_statsfile_timestamp(Oid databaseid, bool permanent,
--- 4277,4294 ----
  		return false;
  	}
  
+ 	/*
+ 	 * Read archiver stats struct
+ 	 */
+ 	if (fread(&myArchiverStats, 1, sizeof(myArchiverStats),
+ 			  fpin) != sizeof(myArchiverStats))
+ 	{
+ 		ereport(pgStatRunningInCollector ? LOG : WARNING,
+ 				(errmsg("corrupted statistics file \"%s\"", statfile)));
+ 		FreeFile(fpin);
+ 		return false;
+ 	}
+ 
  	/* By default, we're going to return the timestamp of the global file. */
  	*ts = myGlobalStats.stats_timestamp;
  
***************
*** 4738,4743 **** pgstat_recv_resetsharedcounter(PgStat_MsgResetsharedcounter *msg, int len)
--- 4816,4827 ----
  		memset(&globalStats, 0, sizeof(globalStats));
  		globalStats.stat_reset_timestamp = GetCurrentTimestamp();
  	}
+ 	else if (msg->m_resettarget == RESET_ARCHIVER)
+ 	{
+ 		/* Reset the archiver statistics for the cluster. */
+ 		memset(&archiverStats, 0, sizeof(archiverStats));
+ 		archiverStats.stat_reset_timestamp = GetCurrentTimestamp();
+ 	}
  
  	/*
  	 * Presumably the sender of this message validated the target, don't
***************
*** 4868,4873 **** pgstat_recv_analyze(PgStat_MsgAnalyze *msg, int len)
--- 4952,4984 ----
  
  
  /* ----------
+  * pgstat_recv_archiver() -
+  *
+  *	Process a ARCHIVER message.
+  * ----------
+  */
+ static void
+ pgstat_recv_archiver(PgStat_MsgArchiver *msg, int len)
+ {
+ 	if (msg->m_failed)
+ 	{
+ 		/* Failed archival attempt */
+ 		++archiverStats.failed_attempts;
+ 		memcpy(archiverStats.last_failed_wal, msg->m_xlog,
+ 			sizeof(archiverStats.last_failed_wal));
+ 		archiverStats.last_failed_wal_timestamp = msg->m_timestamp;
+ 	}
+ 	else
+ 	{
+ 		/* Successful archival operation */
+ 		++archiverStats.archived_wals;
+ 		memcpy(archiverStats.last_archived_wal, msg->m_xlog,
+ 			sizeof(archiverStats.last_archived_wal));
+ 		archiverStats.last_archived_wal_timestamp = msg->m_timestamp;
+ 	}
+ }
+ 
+ /* ----------
   * pgstat_recv_bgwriter() -
   *
   *	Process a BGWRITER message.
*** a/src/backend/utils/adt/pgstatfuncs.c
--- b/src/backend/utils/adt/pgstatfuncs.c
***************
*** 87,92 **** extern Datum pg_stat_get_db_temp_bytes(PG_FUNCTION_ARGS);
--- 87,94 ----
  extern Datum pg_stat_get_db_blk_read_time(PG_FUNCTION_ARGS);
  extern Datum pg_stat_get_db_blk_write_time(PG_FUNCTION_ARGS);
  
+ extern Datum pg_stat_get_archiver(PG_FUNCTION_ARGS);
+ 
  extern Datum pg_stat_get_bgwriter_timed_checkpoints(PG_FUNCTION_ARGS);
  extern Datum pg_stat_get_bgwriter_requested_checkpoints(PG_FUNCTION_ARGS);
  extern Datum pg_stat_get_checkpoint_write_time(PG_FUNCTION_ARGS);
***************
*** 1712,1714 **** pg_stat_reset_single_function_counters(PG_FUNCTION_ARGS)
--- 1714,1783 ----
  
  	PG_RETURN_VOID();
  }
+ 
+ Datum
+ pg_stat_get_archiver(PG_FUNCTION_ARGS)
+ {
+ 	TupleDesc	tupdesc;
+ 	Datum		values[7];
+ 	bool		nulls[7];
+ 	PgStat_ArchiverStats *archiver_stats;
+ 
+ 	/* Initialise values and NULL flags arrays */
+ 	MemSet(values, 0, sizeof(values));
+ 	MemSet(nulls, 0, sizeof(nulls));
+ 
+ 	/* Initialise attributes information in the tuple descriptor */
+ 	tupdesc = CreateTemplateTupleDesc(7, false);
+ 	TupleDescInitEntry(tupdesc, (AttrNumber) 1, "archived_wals",
+ 					   INT8OID, -1, 0);
+ 	TupleDescInitEntry(tupdesc, (AttrNumber) 2, "last_archived_wal",
+ 					   TEXTOID, -1, 0);
+ 	TupleDescInitEntry(tupdesc, (AttrNumber) 3, "last_archived_wal_time",
+ 					   TIMESTAMPTZOID, -1, 0);
+ 	TupleDescInitEntry(tupdesc, (AttrNumber) 4, "failed_attempts",
+ 					   INT8OID, -1, 0);
+ 	TupleDescInitEntry(tupdesc, (AttrNumber) 5, "last_failed_wal",
+ 					   TEXTOID, -1, 0);
+ 	TupleDescInitEntry(tupdesc, (AttrNumber) 6, "last_failed_wal_time",
+ 					   TIMESTAMPTZOID, -1, 0);
+ 	TupleDescInitEntry(tupdesc, (AttrNumber) 7, "stats_reset",
+ 					   TIMESTAMPTZOID, -1, 0);
+ 
+ 	BlessTupleDesc(tupdesc);
+ 
+ 	/* Get statistics about the archiver process */
+ 	archiver_stats = pgstat_fetch_stat_archiver();
+ 
+ 	/* Fill values and NULLs */
+ 	values[0] = Int64GetDatum(archiver_stats->archived_wals);
+ 	if (archiver_stats->last_archived_wal == 0)
+ 		nulls[1] = true;
+ 	else
+ 		values[1] = CStringGetTextDatum(archiver_stats->last_archived_wal);
+ 
+ 	if (archiver_stats->last_archived_wal_timestamp == 0)
+ 		nulls[2] = true;
+ 	else
+ 		values[2] = TimestampTzGetDatum(archiver_stats->last_archived_wal_timestamp);
+ 
+ 	values[3] = Int64GetDatum(archiver_stats->failed_attempts);
+ 	if (archiver_stats->last_failed_wal == 0)
+ 		nulls[4] = true;
+ 	else
+ 		values[4] = CStringGetTextDatum(archiver_stats->last_failed_wal);
+ 
+ 	if (archiver_stats->last_failed_wal_timestamp == 0)
+ 		nulls[5] = true;
+ 	else
+ 		values[5] = TimestampTzGetDatum(archiver_stats->last_failed_wal_timestamp);
+ 
+ 	if (archiver_stats->stat_reset_timestamp == 0)
+ 		nulls[6] = true;
+ 	else
+ 		values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
+ 
+ 	/* Returns the record as Datum */
+ 	PG_RETURN_DATUM(HeapTupleGetDatum(
+ 						heap_form_tuple(tupdesc, values, nulls)));
+ }
*** a/src/include/catalog/pg_proc.h
--- b/src/include/catalog/pg_proc.h
***************
*** 2702,2707 **** DATA(insert OID = 2844 (  pg_stat_get_db_blk_read_time	PGNSP PGUID 12 1 0 0 0 f
--- 2702,2709 ----
  DESCR("statistics: block read time, in msec");
  DATA(insert OID = 2845 (  pg_stat_get_db_blk_write_time PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 701 "26" _null_ _null_ _null_ _null_ pg_stat_get_db_blk_write_time _null_ _null_ _null_ ));
  DESCR("statistics: block write time, in msec");
+ DATA(insert OID = 3195 (  pg_stat_get_archiver		PGNSP PGUID 12 1 0 0 0 f f f f f f s 0 0 2249 "" "{20,25,1184,20,25,1184,1184}" "{o,o,o,o,o,o,o}" "{archived_wals,last_archived_wal,last_archived_wal_time,failed_attempts,last_failed_wal,last_failed_wal_time,stats_reset}" _null_ pg_stat_get_archiver _null_ _null_ _null_ ));
+ DESCR("statistics: information about WAL archiver");
  DATA(insert OID = 2769 ( pg_stat_get_bgwriter_timed_checkpoints PGNSP PGUID 12 1 0 0 0 f f f f t f s 0 0 20 "" _null_ _null_ _null_ _null_ pg_stat_get_bgwriter_timed_checkpoints _null_ _null_ _null_ ));
  DESCR("statistics: number of timed checkpoints started by the bgwriter");
  DATA(insert OID = 2770 ( pg_stat_get_bgwriter_requested_checkpoints PGNSP PGUID 12 1 0 0 0 f f f f t f s 0 0 20 "" _null_ _null_ _null_ _null_ pg_stat_get_bgwriter_requested_checkpoints _null_ _null_ _null_ ));
*** a/src/include/pgstat.h
--- b/src/include/pgstat.h
***************
*** 17,22 ****
--- 17,23 ----
  #include "portability/instr_time.h"
  #include "utils/hsearch.h"
  #include "utils/relcache.h"
+ #include "access/xlog_internal.h"
  
  
  /* Values for track_functions GUC variable --- order is significant! */
***************
*** 44,49 **** typedef enum StatMsgType
--- 45,51 ----
  	PGSTAT_MTYPE_AUTOVAC_START,
  	PGSTAT_MTYPE_VACUUM,
  	PGSTAT_MTYPE_ANALYZE,
+ 	PGSTAT_MTYPE_ARCHIVER,
  	PGSTAT_MTYPE_BGWRITER,
  	PGSTAT_MTYPE_FUNCSTAT,
  	PGSTAT_MTYPE_FUNCPURGE,
***************
*** 102,107 **** typedef struct PgStat_TableCounts
--- 104,110 ----
  /* Possible targets for resetting cluster-wide shared values */
  typedef enum PgStat_Shared_Reset_Target
  {
+ 	RESET_ARCHIVER,
  	RESET_BGWRITER
  } PgStat_Shared_Reset_Target;
  
***************
*** 356,361 **** typedef struct PgStat_MsgAnalyze
--- 359,376 ----
  
  
  /* ----------
+  * PgStat_MsgArchiver			Sent by the archiver to update statistics.
+  * ----------
+  */
+ typedef struct PgStat_MsgArchiver
+ {
+ 	PgStat_MsgHdr	m_hdr;
+ 	bool			m_failed; /* Failed attempt */
+ 	char			m_xlog[MAXFNAMELEN];
+ 	TimestampTz		m_timestamp;
+ } PgStat_MsgArchiver;
+ 
+ /* ----------
   * PgStat_MsgBgWriter			Sent by the bgwriter to update statistics.
   * ----------
   */
***************
*** 502,507 **** typedef union PgStat_Msg
--- 517,523 ----
  	PgStat_MsgAutovacStart msg_autovacuum;
  	PgStat_MsgVacuum msg_vacuum;
  	PgStat_MsgAnalyze msg_analyze;
+ 	PgStat_MsgArchiver msg_archiver;
  	PgStat_MsgBgWriter msg_bgwriter;
  	PgStat_MsgFuncstat msg_funcstat;
  	PgStat_MsgFuncpurge msg_funcpurge;
***************
*** 518,524 **** typedef union PgStat_Msg
   * ------------------------------------------------------------
   */
  
! #define PGSTAT_FILE_FORMAT_ID	0x01A5BC9B
  
  /* ----------
   * PgStat_StatDBEntry			The collector's data per database
--- 534,540 ----
   * ------------------------------------------------------------
   */
  
! #define PGSTAT_FILE_FORMAT_ID	0x01A5BC9C
  
  /* ----------
   * PgStat_StatDBEntry			The collector's data per database
***************
*** 612,617 **** typedef struct PgStat_StatFuncEntry
--- 628,647 ----
  
  
  /*
+  * Archiver statistics kept in the stats collector
+  */
+ typedef struct PgStat_ArchiverStats
+ {
+ 	PgStat_Counter archived_wals;
+ 	char last_archived_wal[MAXFNAMELEN];	/* last WAL file archived */
+ 	TimestampTz last_archived_wal_timestamp;	/* last archival success */
+ 	PgStat_Counter failed_attempts;
+ 	char last_failed_wal[MAXFNAMELEN];	/* last WAL file involved in failure */
+ 	TimestampTz last_failed_wal_timestamp;	/* last archival failure */
+ 	TimestampTz stat_reset_timestamp;
+ } PgStat_ArchiverStats;
+ 
+ /*
   * Global statistics kept in the stats collector
   */
  typedef struct PgStat_GlobalStats
***************
*** 863,868 **** extern void pgstat_twophase_postcommit(TransactionId xid, uint16 info,
--- 893,899 ----
  extern void pgstat_twophase_postabort(TransactionId xid, uint16 info,
  						  void *recdata, uint32 len);
  
+ extern void pgstat_send_archiver(const char *xlog, bool failed);
  extern void pgstat_send_bgwriter(void);
  
  /* ----------
***************
*** 875,880 **** extern PgStat_StatTabEntry *pgstat_fetch_stat_tabentry(Oid relid);
--- 906,912 ----
  extern PgBackendStatus *pgstat_fetch_stat_beentry(int beid);
  extern PgStat_StatFuncEntry *pgstat_fetch_stat_funcentry(Oid funcid);
  extern int	pgstat_fetch_stat_numbackends(void);
+ extern PgStat_ArchiverStats *pgstat_fetch_stat_archiver(void);
  extern PgStat_GlobalStats *pgstat_fetch_global(void);
  
  #endif   /* PGSTAT_H */
*** a/src/test/regress/expected/rules.out
--- b/src/test/regress/expected/rules.out
***************
*** 1640,1645 **** pg_stat_all_tables| SELECT c.oid AS relid,
--- 1640,1653 ----
     LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace)))
    WHERE (c.relkind = ANY (ARRAY['r'::"char", 't'::"char", 'm'::"char"]))
    GROUP BY c.oid, n.nspname, c.relname;
+ pg_stat_archiver| SELECT s.archived_wals,
+     s.last_archived_wal,
+     s.last_archived_wal_time,
+     s.failed_attempts,
+     s.last_failed_wal,
+     s.last_failed_wal_time,
+     s.stats_reset
+    FROM pg_stat_get_archiver() s(archived_wals, last_archived_wal, last_archived_wal_time, failed_attempts, last_failed_wal, last_failed_wal_time, stats_reset);
  pg_stat_bgwriter| SELECT pg_stat_get_bgwriter_timed_checkpoints() AS checkpoints_timed,
      pg_stat_get_bgwriter_requested_checkpoints() AS checkpoints_req,
      pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
