18
18
#include "config.h"
19
19
#include "netcdf.h"
20
20
#include "netcdf_filter.h"
21
+ #include "netcdf_meta.h"
21
22
#include "nc4internal.h"
22
23
#include "nc.h" /* from libsrc */
23
24
#include "ncdispatch.h" /* from libdispatch */
24
25
#include "ncutf8.h"
26
+ #include <stdarg.h>
25
27
26
28
/** @internal Number of reserved attributes. These attributes are
27
29
* hidden from the netcdf user, but exist in the implementation
@@ -58,12 +60,77 @@ float nc4_chunk_cache_preemption = CHUNK_CACHE_PREEMPTION; /**< Default chunk ca
58
60
59
61
static int NC4_move_in_NCList (NC * nc , int new_id );
60
62
61
- #ifdef LOGGING
63
+ #if NC_HAS_LOGGING
62
64
/* This is the severity level of messages which will be logged. Use
63
65
severity 0 for errors, 1 for important log messages, 2 for less
64
66
important, etc. */
65
67
int nc_log_level = NC_TURN_OFF_LOGGING ;
66
- #endif /* LOGGING */
68
+ #if NC_HAS_PARALLEL4
69
+ /* File pointer for the parallel I/O log file. */
70
+ FILE * LOG_FILE = NULL ;
71
+ #endif /* NC_HAS_PARALLEL4 */
72
+
73
+ /* This function prints out a message, if the severity of
74
+ * the message is lower than the global nc_log_level. To use it, do
75
+ * something like this:
76
+ *
77
+ * nc_log(0, "this computer will explode in %d seconds", i);
78
+ *
79
+ * After the first arg (the severity), use the rest like a normal
80
+ * printf statement. Output will appear on stderr for sequential
81
+ * builds, and in a file nc4_log_R.log for each process for a parallel
82
+ * build, where R is the rank of the process.
83
+ *
84
+ * Ed Hartnett
85
+ */
86
+ void
87
+ nc_log (int severity , const char * fmt , ...)
88
+ {
89
+ va_list argp ;
90
+ int t ;
91
+ FILE * f = stderr ;
92
+
93
+ /* If the severity is greater than the log level, we don't print
94
+ * this message. */
95
+ if (severity > nc_log_level )
96
+ return ;
97
+
98
+ #if NC_HAS_PARALLEL4
99
+ /* For parallel I/O build, if MPI has been initialized, instead of
100
+ * printing logging output to stderr, it goes to a file for each
101
+ * process. */
102
+ {
103
+ int mpi_initialized ;
104
+ int mpierr ;
105
+
106
+ /* Check to see if MPI has been initialized. */
107
+ if ((mpierr = MPI_Initialized (& mpi_initialized )))
108
+ return ;
109
+
110
+ /* If MPI has been initialized use a log file. */
111
+ assert (LOG_FILE );
112
+ if (mpi_initialized )
113
+ f = LOG_FILE ;
114
+ }
115
+ #endif /* NC_HAS_PARALLEL4 */
116
+
117
+ /* If the severity is zero, this is an error. Otherwise insert that
118
+ many tabs before the message. */
119
+ if (!severity )
120
+ fprintf (f , "ERROR: " );
121
+ for (t = 0 ; t < severity ; t ++ )
122
+ fprintf (f , "\t" );
123
+
124
+ /* Print out the variable list of args with vprintf. */
125
+ va_start (argp , fmt );
126
+ vfprintf (f , fmt , argp );
127
+ va_end (argp );
128
+
129
+ /* Put on a final linefeed. */
130
+ fprintf (f , "\n" );
131
+ fflush (f );
132
+ }
133
+ #endif /* NC_HAS_LOGGING */
67
134
68
135
/**
69
136
* @internal Check and normalize and name.
@@ -1684,13 +1751,74 @@ nc4_normalize_name(const char *name, char *norm_name)
1684
1751
#ifdef ENABLE_SET_LOG_LEVEL
1685
1752
1686
1753
/**
1687
- * @internal Use this to set the global log level. Set it to
1688
- * NC_TURN_OFF_LOGGING (-1) to turn off all logging. Set it to 0 to
1689
- * show only errors, and to higher numbers to show more and more
1690
- * logging details. If logging is not enabled with --enable-logging at
1691
- * configure when building netCDF, this function will do nothing.
1692
- * Note that it is possible to set the log level using the environment
1693
- * variable named _NETCDF_LOG_LEVEL_ (e.g. _export NETCDF_LOG_LEVEL=4_).
1754
+ * Initialize parallel I/O logging. For parallel I/O builds, open log
1755
+ * file, if not opened yet, or increment ref count if already open.
1756
+ *
1757
+ * @author Ed Hartnett
1758
+ */
1759
+ int
1760
+ nc4_init_logging (void )
1761
+ {
1762
+ int ret = NC_NOERR ;
1763
+
1764
+ #if NC_HAS_LOGGING
1765
+ #if NC_HAS_PARALLEL4
1766
+ if (!LOG_FILE && nc_log_level >= 0 )
1767
+ {
1768
+ char log_filename [NC_MAX_NAME ];
1769
+ int my_rank = 0 ;
1770
+ int mpierr ;
1771
+ int mpi_initialized ;
1772
+
1773
+ /* If MPI has been initialized find the rank. */
1774
+ if ((mpierr = MPI_Initialized (& mpi_initialized )))
1775
+ return NC_EMPI ;
1776
+ if (mpi_initialized )
1777
+ {
1778
+ if ((mpierr = MPI_Comm_rank (MPI_COMM_WORLD , & my_rank )))
1779
+ return NC_EMPI ;
1780
+ }
1781
+
1782
+ /* Create a filename with the rank in it. */
1783
+ sprintf (log_filename , "nc4_log_%d.log" , my_rank );
1784
+
1785
+ /* Open a file for this rank to log messages. */
1786
+ if (!(LOG_FILE = fopen (log_filename , "w" )))
1787
+ return NC_EINTERNAL ;
1788
+ }
1789
+ #endif /* NC_HAS_PARALLEL4 */
1790
+ #endif /* NC_HAS_LOGGING */
1791
+
1792
+ return ret ;
1793
+ }
1794
+
1795
+ /**
1796
+ * Finalize logging - close parallel I/O log files, if open. This does
1797
+ * nothing if logging is not enabled.
1798
+ *
1799
+ * @author Ed Hartnett
1800
+ */
1801
+ void
1802
+ nc4_finalize_logging (void )
1803
+ {
1804
+ #if NC_HAS_LOGGING
1805
+ #if NC_HAS_PARALLEL4
1806
+ if (LOG_FILE )
1807
+ {
1808
+ fclose (LOG_FILE );
1809
+ LOG_FILE = NULL ;
1810
+ }
1811
+ #endif /* NC_HAS_PARALLEL4 */
1812
+ #endif /* NC_HAS_LOGGING */
1813
+ }
1814
+
1815
+ /**
1816
+ * Use this to set the global log level.
1817
+ *
1818
+ * Set it to NC_TURN_OFF_LOGGING (-1) to turn off all logging. Set it
1819
+ * to 0 to show only errors, and to higher numbers to show more and
1820
+ * more logging details. If logging is not enabled when building
1821
+ * netCDF, this function will do nothing.
1694
1822
*
1695
1823
* @param new_level The new logging level.
1696
1824
*
@@ -1700,16 +1828,30 @@ nc4_normalize_name(const char *name, char *norm_name)
1700
1828
int
1701
1829
nc_set_log_level (int new_level )
1702
1830
{
1703
- #ifdef LOGGING
1831
+ #if NC_HAS_LOGGING
1704
1832
/* Remember the new level. */
1705
1833
nc_log_level = new_level ;
1706
- LOG ((4 , "log_level changed to %d" , nc_log_level ));
1707
- #endif /*LOGGING */
1708
- return 0 ;
1834
+
1835
+ #if NC_HAS_PARALLEL4
1836
+ /* For parallel I/O builds, call the log init/finalize functions
1837
+ * as needed, to open and close the log files. */
1838
+ if (new_level >= 0 )
1839
+ {
1840
+ if (!LOG_FILE )
1841
+ nc4_init_logging ();
1842
+ }
1843
+ else
1844
+ nc4_finalize_logging ();
1845
+ #endif /* NC_HAS_PARALLEL4 */
1846
+
1847
+ LOG ((1 , "log_level changed to %d" , nc_log_level ));
1848
+ #endif /*NC_HAS_LOGGING */
1849
+
1850
+ return NC_NOERR ;
1709
1851
}
1710
1852
#endif /* ENABLE_SET_LOG_LEVEL */
1711
1853
1712
- #ifdef LOGGING
1854
+ #if NC_HAS_LOGGING
1713
1855
#define MAX_NESTS 10
1714
1856
/**
1715
1857
* @internal Recursively print the metadata of a group.
@@ -1878,7 +2020,7 @@ log_metadata_nc(NC_FILE_INFO_T *h5)
1878
2020
return NC_NOERR ;
1879
2021
}
1880
2022
1881
- #endif /*LOGGING */
2023
+ #endif /*NC_HAS_LOGGING */
1882
2024
1883
2025
/**
1884
2026
* @internal Show the in-memory metadata for a netcdf file. This
@@ -1895,7 +2037,7 @@ int
1895
2037
NC4_show_metadata (int ncid )
1896
2038
{
1897
2039
int retval = NC_NOERR ;
1898
- #ifdef LOGGING
2040
+ #if NC_HAS_LOGGING
1899
2041
NC_FILE_INFO_T * h5 ;
1900
2042
int old_log_level = nc_log_level ;
1901
2043
@@ -1907,7 +2049,7 @@ NC4_show_metadata(int ncid)
1907
2049
nc_log_level = 2 ;
1908
2050
retval = log_metadata_nc (h5 );
1909
2051
nc_log_level = old_log_level ;
1910
- #endif /*LOGGING */
2052
+ #endif /*NC_HAS_LOGGING */
1911
2053
return retval ;
1912
2054
}
1913
2055
0 commit comments