From af6171afa608fd3ddf1bee505d72d5e599c820b2 Mon Sep 17 00:00:00 2001 From: Robert Butora <robert.butora@inaf.it> Date: Sat, 21 Sep 2024 14:13:14 +0200 Subject: [PATCH] all: set logging levels --- auth/src/main/java/AuthPolicy.java | 40 ++++++------- auth/src/main/java/AuthPolicyDb.java | 29 +++++---- auth/src/main/java/IA2TokenConvFilter.java | 10 ++-- auth/src/main/java/IamSigningKeyResolver.java | 12 ++-- auth/src/main/java/IamTokenFilter.java | 40 +++++++------ auth/src/main/java/IntrospectResponse.java | 4 +- auth/src/main/java/NeaSigningKeyResolver.java | 12 ++-- auth/src/main/java/NeaTokenFilter.java | 10 ++-- auth/src/main/java/NeaTokenSettings.java | 2 +- .../src/main/java/common/Subsurvey.java | 14 ++--- .../servlet/src/main/java/ops/CutArgs.java | 8 +-- .../servlet/src/main/java/ops/JdlMCutout.java | 10 ++-- .../servlet/src/main/java/ops/Regrid.java | 24 ++++---- .../servlet/src/main/java/ops/Reproject.java | 4 +- .../servlet/src/main/java/ops/SodaImpl.java | 36 ++++++----- .../servlet/src/main/java/ops/VlkbAmqp.java | 56 +++++++++--------- .../servlet/src/main/java/ops/VlkbCli.java | 42 ++++++------- .../src/main/java/ops/amqp/JsonDecoder.java | 4 +- .../src/main/java/ops/amqp/JsonEncoder.java | 6 +- .../src/main/java/ops/amqp/RpcOverAmqp.java | 16 ++--- .../src/main/java/ops/cli/ExecCmd.java | 15 +++-- .../main/java/resolver/ResolverByObsCore.java | 14 ++--- .../java/resolver/ResolverByObsCoreDb.java | 24 ++++---- .../main/java/resolver/ResolverFromId.java | 10 ++-- .../src/main/java/webapi/AuthZFilter.java | 12 ++-- .../src/main/java/webapi/AuthZSettings.java | 6 +- .../src/main/java/webapi/ServletCutout.java | 50 ++++++++-------- .../src/main/java/webapi/UWSMCutoutWork.java | 6 +- .../src/main/java/webapi/UWSMergeWork.java | 6 +- .../java/webapi/output/XmlSerializer.java | 6 +- java-libs/lib/vlkb-volib-0.9.1-SNAPSHOT.jar | Bin 28614 -> 28682 bytes 31 files changed, 272 insertions(+), 256 deletions(-) diff --git a/auth/src/main/java/AuthPolicy.java b/auth/src/main/java/AuthPolicy.java index 8c3d60f..0471714 100644 --- a/auth/src/main/java/AuthPolicy.java +++ b/auth/src/main/java/AuthPolicy.java @@ -53,7 +53,7 @@ public class AuthPolicy access = Access.PUBLIC_AND_AUTHORIZED_PRIVATE; - LOGGER.info("User [Groups]: " + userName + " [ " + String.join(" ", userGroups) + " ]" ); + LOGGER.finer("User [Groups]: " + userName + " [ " + String.join(" ", userGroups) + " ]" ); } @@ -67,7 +67,7 @@ public class AuthPolicy userName = null; userGroups = null; userGroupsValid = false; - LOGGER.info("Non authenticated request (UserPrincipal null in HttpServletRequest)"); + LOGGER.finer("Non authenticated request (UserPrincipal null in HttpServletRequest)"); } else { @@ -81,12 +81,12 @@ public class AuthPolicy access = Access.PUBLIC_AND_AUTHORIZED_PRIVATE; - LOGGER.info("User [Groups]: " + userName + " [ " + String.join(" ", userGroups) + " ]" ); + LOGGER.finer("User [Groups]: " + userName + " [ " + String.join(" ", userGroups) + " ]" ); } else { userName = principal.getName(); - LOGGER.info("DBG principal not instance of VlkbUser, but has user-name: " + userName); + LOGGER.finer("DBG principal not instance of VlkbUser, but has user-name: " + userName); userGroups = new String[]{""};//{"VLKB.groupA", "AllPrivate"}; // was for shiro userGroupsValid = true; access = Access.PUBLIC_AND_AUTHORIZED_PRIVATE; @@ -163,13 +163,13 @@ public class AuthPolicy this.dbUserName = dbUserName; this.dbPassword = dbPassword; - LOGGER.info("with String[] trace"); + LOGGER.finer("with String[] trace"); return filterAuthorized(new ArrayList<String>(Arrays.asList(pubdidArr)), dbConnUrl); } private String[] filterAuthorized(ArrayList<String> pubdidList, String dbConnUrl) { - //LOGGER.info("with List <String> trace"); + //LOGGER.fine("with List <String> trace"); switch(access) { case PUBLIC_ONLY : @@ -189,25 +189,25 @@ public class AuthPolicy private void filterNotPublic(ArrayList<String> pubdids, String dbConnUrl) { - LOGGER.info("trace"); + LOGGER.fine("trace"); assert pubdids != null; - //LOGGER.info("PublisherDID list original : " + String.join(" ", pubdids)); + //LOGGER.finer("PublisherDID list original : " + String.join(" ", pubdids)); List<AuthPolicyDb.PubdidGroups> privateUniqPubdids = db_queryPrivateUniqPubdidGroups(dbConnUrl, pubdids); List<String> notAuthorizedUniqPubdids = pubdidsNotPublic(privateUniqPubdids, userGroups); - LOGGER.info("AuthZ removes: " + String.join(" ", notAuthorizedUniqPubdids)); + LOGGER.finest("AuthZ removes: " + String.join(" ", notAuthorizedUniqPubdids)); removeNotAuthorized(pubdids, notAuthorizedUniqPubdids); - //LOGGER.info("PublisherDID list filtered : " + (pubdids.isEmpty() ? "" : String.join(" ", pubdids))); + //LOGGER.finest("PublisherDID list filtered : " + (pubdids.isEmpty() ? "" : String.join(" ", pubdids))); } private List<String> pubdidsNotPublic(List<AuthPolicyDb.PubdidGroups> pubdidList, String[] userGroups) { - LOGGER.info("trace"); - //LOGGER.info("userGroups: " + String.join(" ",userGroups)); + LOGGER.fine("trace"); + //LOGGER.finer("userGroups: " + String.join(" ",userGroups)); List<String> pubdidsNotAuthorizedList = new LinkedList<String>(); ListIterator<AuthPolicyDb.PubdidGroups> it = pubdidList.listIterator(); @@ -216,7 +216,7 @@ public class AuthPolicy { AuthPolicyDb.PubdidGroups pubdidGroups = it.next(); - //LOGGER.info(pubdidGroups.pubdid + " : " + String.join(" ",pubdidGroups.groups)); + //LOGGER.finest(pubdidGroups.pubdid + " : " + String.join(" ",pubdidGroups.groups)); if( true )// isIntersectionEmpty(pubdidGroups.groups, userGroups) ) { @@ -231,18 +231,18 @@ public class AuthPolicy private void filterNotAuthorized(ArrayList<String> pubdids, String dbConnUrl) { - LOGGER.info("trace"); + LOGGER.fine("trace"); assert pubdids != null; - //LOGGER.info("PublisherDID list original : " + String.join(" ", pubdids)); + //LOGGER.finer("PublisherDID list original : " + String.join(" ", pubdids)); List<AuthPolicyDb.PubdidGroups> privateUniqPubdids = db_queryPrivateUniqPubdidGroups(dbConnUrl, pubdids); List<String> notAuthorizedUniqPubdids = pubdidsNotAuthorized(privateUniqPubdids, userGroups); - LOGGER.info("AuthZ removes: " + String.join(" ", notAuthorizedUniqPubdids)); + LOGGER.finest("AuthZ removes: " + String.join(" ", notAuthorizedUniqPubdids)); removeNotAuthorized(pubdids, notAuthorizedUniqPubdids); - //LOGGER.info("PublisherDID list filtered : " + (pubdids.isEmpty() ? "" : String.join(" ", pubdids))); + //LOGGER.finest("PublisherDID list filtered : " + (pubdids.isEmpty() ? "" : String.join(" ", pubdids))); } @@ -296,8 +296,8 @@ public class AuthPolicy private List<String> pubdidsNotAuthorized(List<AuthPolicyDb.PubdidGroups> pubdidList, String[] userGroups) { - LOGGER.info("trace"); - //LOGGER.info("userGroups: " + String.join(" ",userGroups)); + LOGGER.fine("trace"); + //LOGGER.finer("userGroups: " + String.join(" ",userGroups)); List<String> pubdidsNotAuthorizedList = new LinkedList<String>(); ListIterator<AuthPolicyDb.PubdidGroups> it = pubdidList.listIterator(); @@ -306,7 +306,7 @@ public class AuthPolicy { AuthPolicyDb.PubdidGroups pubdidGroups = it.next(); - //LOGGER.info(pubdidGroups.pubdid + " : " + String.join(" ",pubdidGroups.groups)); + //LOGGER.finest(pubdidGroups.pubdid + " : " + String.join(" ",pubdidGroups.groups)); if( isIntersectionEmpty(pubdidGroups.groups, userGroups) ) { diff --git a/auth/src/main/java/AuthPolicyDb.java b/auth/src/main/java/AuthPolicyDb.java index 9f737ec..7eeb8a5 100644 --- a/auth/src/main/java/AuthPolicyDb.java +++ b/auth/src/main/java/AuthPolicyDb.java @@ -104,7 +104,7 @@ public class AuthPolicyDb //String TheQuery = "SELECT obs_publisher_did,groups FROM permissions " // + "WHERE (obs_publisher_did IN (\'"+commaSepObscorePubdids+"\'));"; - //LOGGER.info(TheQuery); + //LOGGER.finest(TheQuery); List<PubdidGroups> pubdidGroups = new LinkedList<PubdidGroups>(); try @@ -134,7 +134,7 @@ public class AuthPolicyDb } catch (ClassNotFoundException e) { - LOGGER.info("DB driver "+ DB_DRIVER +" not found: " + e.getMessage()); + LOGGER.severe("DB driver "+ DB_DRIVER +" not found: " + e.getMessage()); e.printStackTrace(); } finally @@ -148,21 +148,21 @@ public class AuthPolicyDb private void closeAll() { - if(res != null ) try { res.close(); } catch(Exception e) {LOGGER.info("DB ResultSet::close() failed");} - if(st != null ) try { st.close(); } catch(Exception e) {LOGGER.info("DB Statement::close() failed");} - if(conn != null ) try { conn.close();} catch(Exception e) {LOGGER.info("DB Connection::close() failed");} + if(res != null ) try { res.close(); } catch(Exception e) {LOGGER.severe("DB ResultSet::close() failed");} + if(st != null ) try { st.close(); } catch(Exception e) {LOGGER.severe("DB Statement::close() failed");} + if(conn != null ) try { conn.close();} catch(Exception e) {LOGGER.severe("DB Connection::close() failed");} } private void logSqlExInfo(SQLException se){ /* dbconn.print_class_vars(); */ - System.err.println("SQLState : " + se.getSQLState()); - System.err.println("ErrorCode: " + se.getErrorCode()); - System.err.println("Message : " + se.getMessage()); + LOGGER.severe("SQLState : " + se.getSQLState()); + LOGGER.severe("ErrorCode: " + se.getErrorCode()); + LOGGER.severe("Message : " + se.getMessage()); Throwable t = se.getCause(); while(t != null) { - System.err.println("Cause: " + t); + LOGGER.severe("Cause: " + t); t = t.getCause(); } } @@ -184,8 +184,7 @@ public class AuthPolicyDb DriverManager.registerDriver(new org.postgresql.Driver()); */ - /*LOGGER.info(getClasspathString());*/ - LOGGER.info(getRegisteredDriverList()); + LOGGER.finest(getRegisteredDriverList()); // FIXME seems DriverManager expects jdbc:postgresql driver scheme, it does not support postgresql:// scheme // additionally: @@ -195,7 +194,7 @@ public class AuthPolicyDb // by extracting userName and password from the URL-string and prepending 'jdbc:' // - /* LOGGER.info("DBMS URL: " + dbConnUrl); + /* LOGGER.finest("DBMS URL: " + dbConnUrl); URI dbConnUri = new URI(dbConnUrl); String userInfoString = dbConnUri.getUserInfo(); @@ -210,9 +209,9 @@ public class AuthPolicyDb String password = userInfo[1]; String dbConnJdbcUrl = "jdbc:" + dbConnUrl.replace(userInfoString + "@", ""); - */ LOGGER.info("DBMS URL: " + dbConnUrl); - LOGGER.info("DBMS userName: " + dbUserName); - LOGGER.info("DBMS password: " + dbPassword); + */ LOGGER.finest("DBMS URL: " + dbConnUrl); + LOGGER.finest("DBMS userName: " + dbUserName); + LOGGER.finest("DBMS password: " + dbPassword); conn = DriverManager.getConnection(dbConnUrl, dbUserName, dbPassword); diff --git a/auth/src/main/java/IA2TokenConvFilter.java b/auth/src/main/java/IA2TokenConvFilter.java index a64c181..b91cfac 100644 --- a/auth/src/main/java/IA2TokenConvFilter.java +++ b/auth/src/main/java/IA2TokenConvFilter.java @@ -21,25 +21,25 @@ import java.security.Principal; public class IA2TokenConvFilter implements Filter { - private static final Logger LOGGER = Logger.getLogger("IA2TokenConvFilter"); + private static final Logger LOGGER = Logger.getLogger(IA2TokenConvFilter.class.getName()); @Override public void init(FilterConfig fc) throws ServletException { - LOGGER.info("trace"); + LOGGER.fine("trace"); } @Override public void destroy() { - LOGGER.info("trace"); + LOGGER.fine("trace"); } @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { - LOGGER.info("trace"); + LOGGER.fine("trace"); HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; @@ -47,7 +47,7 @@ public class IA2TokenConvFilter implements Filter String authHeader = request.getHeader("Authorization"); if (authHeader != null) { - LOGGER.info("Authorization header: " + authHeader.substring(0, 7+60) + " ..."); + LOGGER.finer("Authorization header: " + authHeader.substring(0, 7+60) + " ..."); if (authHeader.startsWith("Bearer ")) { diff --git a/auth/src/main/java/IamSigningKeyResolver.java b/auth/src/main/java/IamSigningKeyResolver.java index ff89893..8c64a67 100644 --- a/auth/src/main/java/IamSigningKeyResolver.java +++ b/auth/src/main/java/IamSigningKeyResolver.java @@ -59,7 +59,7 @@ public class IamSigningKeyResolver extends SigningKeyResolverAdapter @Override public Key resolveSigningKey(JwsHeader jwsHeader, Claims claims) { - LOGGER.info( "IamSigningKeyResolver::resolveSigningKey" ); + LOGGER.fine( "trace" ); //inspect the header or claims, lookup and return the signing key @@ -83,7 +83,7 @@ public class IamSigningKeyResolver extends SigningKeyResolverAdapter private Key lookupVerificationKey(String keyId) throws Exception, GeneralSecurityException { - LOGGER.info( "IamSigningKeyResolver::lookupVerificationKey" ); + LOGGER.fine( "trace" ); String jsonKeys = doHttps(); @@ -95,7 +95,7 @@ public class IamSigningKeyResolver extends SigningKeyResolverAdapter private String doHttps() throws Exception { - LOGGER.info("doHttps : " + keysURL); + LOGGER.fine("trace keysURL : " + keysURL); URL myUrl = new URL(keysURL); HttpsURLConnection conn = (HttpsURLConnection)myUrl.openConnection(); @@ -118,7 +118,7 @@ public class IamSigningKeyResolver extends SigningKeyResolverAdapter private Key getKeyFromKeys(String jsonKeys, String keyId) throws JsonProcessingException, GeneralSecurityException, IOException { - LOGGER.info( "IamSigningKeyResolver::getKeyFromKeys"); + LOGGER.fine( "trace" ); Key key = null; @@ -131,13 +131,13 @@ public class IamSigningKeyResolver extends SigningKeyResolverAdapter { String nodeContent = mapper.writeValueAsString(node); - LOGGER.info("key: " + nodeContent); + LOGGER.finest("key: " + nodeContent); Jwk<?> jwk = Jwks.parser().build().parse(nodeContent); String jwkkid = jwk.getId(); - LOGGER.info("kid-token : " + keyId + "kid-store : " + jwkkid + " key-type: " + jwk.getType()); + LOGGER.finest("kid-token : " + keyId + "kid-store : " + jwkkid + " key-type: " + jwk.getType()); if(keyId.equals(jwkkid)) { diff --git a/auth/src/main/java/IamTokenFilter.java b/auth/src/main/java/IamTokenFilter.java index f434f82..b4f255f 100644 --- a/auth/src/main/java/IamTokenFilter.java +++ b/auth/src/main/java/IamTokenFilter.java @@ -35,7 +35,7 @@ import javax.servlet.ServletOutputStream; public class IamTokenFilter implements Filter { - private static final Logger LOGGER = Logger.getLogger("IamTokenFilter"); + private static final Logger LOGGER = Logger.getLogger(IamTokenFilter.class.getName()); private static final IamTokenSettings settings = IamTokenSettings.getInstance(); final String RESPONSE_ENCODING = "utf-8"; @@ -64,7 +64,7 @@ public class IamTokenFilter implements Filter if(authHeader==null) { final String AUTH_ERR = "Request without Authorization header. Only authenticated requests allowed."; - LOGGER.info(AUTH_ERR); + LOGGER.warning(AUTH_ERR); sendAuthenticationError((HttpServletResponse)resp, writer, AUTH_ERR); } else @@ -73,7 +73,7 @@ public class IamTokenFilter implements Filter if (authHeader.startsWith("Bearer ") && (authHeader.length() > "Bearer ".length())) { - LOGGER.info("Request with Authorization header and has Bearer entry"); + LOGGER.warning("Request with Authorization header and has Bearer entry"); String token = authHeader.substring("Bearer ".length()).trim(); doFilterBearer(req, token, resp, chain); @@ -82,7 +82,7 @@ public class IamTokenFilter implements Filter { final String AUTH_ERR = "Authorization header with Bearer-token expected, but it starts with : " + authHeader.substring(0, "Bearer ".length()) + "..."; - LOGGER.info(AUTH_ERR); + LOGGER.warning(AUTH_ERR); sendUsageError((HttpServletResponse)resp, writer, AUTH_ERR); } } @@ -94,6 +94,8 @@ public class IamTokenFilter implements Filter private void doFilterBearer(ServletRequest req, String token, ServletResponse resp, FilterChain chain) throws IOException, ServletException { + LOGGER.fine("trace"); + HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse)resp; @@ -112,42 +114,42 @@ public class IamTokenFilter implements Filter String ivoidPath = ivoid.getLocalPart(); String tokenPath = insResp.getPathFromStorageReadScope(); - LOGGER.info("Path from IVOID: " + ivoidPath); - LOGGER.info("Path from token: " + tokenPath); + LOGGER.finest("Path from IVOID: " + ivoidPath); + LOGGER.finest("Path from token: " + tokenPath); if(tokenPath.endsWith(ivoidPath)) { - LOGGER.info("Access authorized."); + LOGGER.finest("Access authorized."); chain.doFilter(request, response); } else { final String AUTH_ERR = "Bearer token does not authorize access to : " + ivoidPath; - LOGGER.info(AUTH_ERR); + LOGGER.finer(AUTH_ERR); sendAuthorizationError(response, writer, AUTH_ERR); } } else { final String AUTH_ERR = "Bearer-token is inactive."; - LOGGER.info(AUTH_ERR); + LOGGER.finer(AUTH_ERR); sendAuthorizationError(response, writer, AUTH_ERR); } } catch(IndexOutOfBoundsException ex) { - LOGGER.info("IndexOutOfBoundsException: " + ex.getMessage()); + LOGGER.warning("IndexOutOfBoundsException: " + ex.getMessage()); sendUsageError(response, writer, ex.getMessage()); } catch(IllegalArgumentException ex) { - LOGGER.info("IllegalArgumentException: " + ex.getMessage()); + LOGGER.warning("IllegalArgumentException: " + ex.getMessage()); sendUsageError(response, writer, ex.getMessage()); } catch(Exception ex) { - LOGGER.info("Exception: " + ex.getMessage()); + LOGGER.severe("Exception: " + ex.getMessage()); ex.printStackTrace(); sendError(response, writer, ex.toString()); } @@ -240,9 +242,9 @@ public class IamTokenFilter implements Filter String qString = request.getQueryString(); if(qString == null) - LOGGER.info(request.getRequestURL().toString()); + LOGGER.finest(request.getRequestURL().toString()); else - LOGGER.info(request.getRequestURL() + " " + qString); + LOGGER.finest(request.getRequestURL() + " " + qString); String authHeader = request.getHeader("Authorization"); if (authHeader == null) @@ -255,7 +257,7 @@ public class IamTokenFilter implements Filter } else { - LOGGER.info("Request without Authorization header, no Principal added"); + LOGGER.finest("Request without Authorization header, no Principal added"); response.sendError(HttpServletResponse.SC_BAD_REQUEST, "No Authorization in HTTP-header. Only authorized requests allowed."); } @@ -266,7 +268,7 @@ public class IamTokenFilter implements Filter if (authHeader.startsWith("Bearer ") && (authHeader.length() > "Bearer ".length())) { - LOGGER.info("Request with Authorization header and has Bearer entry"); + LOGGER.finest("Request with Authorization header and has Bearer entry"); String jws = authHeader.substring("Bearer ".length()); @@ -345,7 +347,7 @@ public class IamTokenFilter implements Filter Claims claims = jws.getBody(); - LOGGER.info("scope: " + (String)claims.get("scope")); + LOGGER.finest("scope: " + (String)claims.get("scope")); List<String> scopes = parseScopes(claims); @@ -359,11 +361,11 @@ public class IamTokenFilter implements Filter } } - LOGGER.info("storage.read: " + storageReadScope); + LOGGER.finest("storage.read: " + storageReadScope); String path = storageReadScope.substring(storageReadScope.lastIndexOf(":") + 1); - LOGGER.info("path: " + path); + LOGGER.finest("path: " + path); // set User/Principal diff --git a/auth/src/main/java/IntrospectResponse.java b/auth/src/main/java/IntrospectResponse.java index 4ac4b8b..e7c0f4e 100644 --- a/auth/src/main/java/IntrospectResponse.java +++ b/auth/src/main/java/IntrospectResponse.java @@ -20,7 +20,7 @@ import com.fasterxml.jackson.annotation.JsonAutoDetect; class IntrospectResponse { - private static final Logger LOGGER = Logger.getLogger("IntrospectResponse"); + private static final Logger LOGGER = Logger.getLogger(IntrospectResponse.class.getName()); public boolean active; public String scope; @@ -59,7 +59,7 @@ class IntrospectResponse private String doHttps(String uPass, String url, String postParams) throws Exception { - LOGGER.info("doHttps : " + url); + LOGGER.fine("url : " + url); URL myUrl = new URL(url); HttpsURLConnection conn = (HttpsURLConnection)myUrl.openConnection(); diff --git a/auth/src/main/java/NeaSigningKeyResolver.java b/auth/src/main/java/NeaSigningKeyResolver.java index 72af234..4ec28dc 100644 --- a/auth/src/main/java/NeaSigningKeyResolver.java +++ b/auth/src/main/java/NeaSigningKeyResolver.java @@ -63,7 +63,7 @@ public class NeaSigningKeyResolver extends SigningKeyResolverAdapter private String doHttps() throws Exception { - LOGGER.info("doHttps : " + keysURL); + LOGGER.fine("keysURL : " + keysURL); URL myUrl = new URL(keysURL); HttpsURLConnection conn = (HttpsURLConnection)myUrl.openConnection(); @@ -105,7 +105,7 @@ public class NeaSigningKeyResolver extends SigningKeyResolverAdapter private String getCertFromKeys(String jsonKeys, String keyId) throws JsonProcessingException, GeneralSecurityException, IOException { - LOGGER.info( "NeaSigningKeyResolver::getCertFromKeys"); + LOGGER.fine( "trace"); ObjectMapper mapper = new ObjectMapper(); @@ -119,7 +119,7 @@ public class NeaSigningKeyResolver extends SigningKeyResolverAdapter String nodeContent = mapper.writeValueAsString(node); NeaKey key = mapper.readValue(nodeContent,NeaKey.class); - LOGGER.info("keyId : " + keyId + LOGGER.finest("keyId : " + keyId +"\nKey::kid : " + key.kid); if(keyId.equals(key.kid)) @@ -138,7 +138,7 @@ public class NeaSigningKeyResolver extends SigningKeyResolverAdapter private PublicKey getPublicKeyFromPemCert(String certBase64) throws GeneralSecurityException { - LOGGER.info( "NeaSigningKeyResolver::getPublicKeyFromPemCert"); + LOGGER.fine( "trace" ); CertificateFactory fac = CertificateFactory.getInstance("X509"); ByteArrayInputStream in = new ByteArrayInputStream(Base64.getDecoder().decode(certBase64)); @@ -152,7 +152,7 @@ public class NeaSigningKeyResolver extends SigningKeyResolverAdapter private Key lookupVerificationKey(String keyId) throws Exception, GeneralSecurityException { - LOGGER.info( "NeaSigningKeyResolver::lookupVerificationKey" ); + LOGGER.fine( "trace" ); String jsonKeys = doHttps(); @@ -169,7 +169,7 @@ public class NeaSigningKeyResolver extends SigningKeyResolverAdapter @Override public Key resolveSigningKey(JwsHeader jwsHeader, Claims claims) { - LOGGER.info( "NeaSigningKeyResolver::resolveSigningKey" ); + LOGGER.fine( "trace" ); //inspect the header or claims, lookup and return the signing key diff --git a/auth/src/main/java/NeaTokenFilter.java b/auth/src/main/java/NeaTokenFilter.java index f24dc4c..cbb5fc2 100644 --- a/auth/src/main/java/NeaTokenFilter.java +++ b/auth/src/main/java/NeaTokenFilter.java @@ -34,7 +34,7 @@ import javax.servlet.http.HttpServletResponse; public class NeaTokenFilter implements Filter { - private static final Logger LOGGER = Logger.getLogger("NeaTokenFilter"); + private static final Logger LOGGER = Logger.getLogger(NeaTokenFilter.class.getName()); private static final NeaTokenSettings settings = NeaTokenSettings.getInstance(); final String resourceId = settings.security.resourceId; //"vlkb" @@ -57,9 +57,9 @@ public class NeaTokenFilter implements Filter String qString = request.getQueryString(); if(qString == null) - LOGGER.info(request.getRequestURL().toString()); + LOGGER.finest(request.getRequestURL().toString()); else - LOGGER.info(request.getRequestURL() + " " + qString); + LOGGER.finest(request.getRequestURL() + " " + qString); String authHeader = request.getHeader("Authorization"); if (authHeader == null) @@ -72,7 +72,7 @@ public class NeaTokenFilter implements Filter } else { - LOGGER.info("Request without Authorization header, no Principal added"); + LOGGER.warning("Request without Authorization header, no Principal added"); response.sendError(HttpServletResponse.SC_BAD_REQUEST, "No Authorization in HTTP-header. Only authorized requests allowed."); } @@ -83,7 +83,7 @@ public class NeaTokenFilter implements Filter if (authHeader.startsWith("Bearer ") && (authHeader.length() > "Bearer ".length())) { - LOGGER.info("Request with Authorization header and has Bearer entry"); + LOGGER.finer("Request with Authorization header and has Bearer entry"); String jws = authHeader.substring("Bearer ".length()); diff --git a/auth/src/main/java/NeaTokenSettings.java b/auth/src/main/java/NeaTokenSettings.java index ce71c44..766d390 100644 --- a/auth/src/main/java/NeaTokenSettings.java +++ b/auth/src/main/java/NeaTokenSettings.java @@ -20,7 +20,7 @@ import java.util.ArrayList; class NeaTokenSettings { - private static final Logger LOGGER = Logger.getLogger("NeaTokenSettings"); + //private static final Logger LOGGER = Logger.getLogger(NeaTokenSettings.class.getName()); static final String VLKB_PROPERTIES = "neatoken.properties"; diff --git a/data-access/servlet/src/main/java/common/Subsurvey.java b/data-access/servlet/src/main/java/common/Subsurvey.java index d5dfe48..d8f64cf 100644 --- a/data-access/servlet/src/main/java/common/Subsurvey.java +++ b/data-access/servlet/src/main/java/common/Subsurvey.java @@ -15,7 +15,7 @@ import java.util.ArrayList; class Subsurvey { - private static final Logger LOGGER = Logger.getLogger("Subsurvey"); + private static final Logger LOGGER = Logger.getLogger(Subsurvey.class.getName()); String description; String surveyname; @@ -62,7 +62,7 @@ class Subsurvey static public Subsurvey findSubsurveyByStoragePath(Subsurvey[] dbSubsurveys, String storagePath) { - LOGGER.info("trace storagePath: " + storagePath); + LOGGER.fine("trace storagePath: " + storagePath); for(Subsurvey curr : dbSubsurveys) { @@ -109,15 +109,15 @@ class Subsurvey public static Subsurvey[] loadSubsurveys(String csvFilename) { - LOGGER.info("trace"); + LOGGER.fine("trace"); /* avoid access files-system if csv-filename not configured */ if( (csvFilename == null) || ( (csvFilename != null) && (csvFilename.length() < 1) ) ) { - LOGGER.warning("csvFilename is empty, metadata not loaded"); + LOGGER.config("csvFilename is empty, metadata not loaded"); return null; } - LOGGER.info("load from: " + csvFilename); + LOGGER.config("load from: " + csvFilename); try { @@ -147,13 +147,13 @@ class Subsurvey } catch(IOException ex) { - LOGGER.info("Error while loading " + csvFilename + " -> " + ex.getMessage()); + LOGGER.warning("While loading " + csvFilename + " -> " + ex.getMessage()); return null; //throw new IllegalStateException("Error while loading " + csvFilename + " file", ex); } catch(CsvValidationException ex) { - LOGGER.info("Error while reading " + csvFilename + " -> " + ex.getMessage()); + LOGGER.warning("While reading " + csvFilename + " -> " + ex.getMessage()); return null; //throw new IllegalStateException("Error while reading " + csvFilename + " file", ex); } diff --git a/data-access/servlet/src/main/java/ops/CutArgs.java b/data-access/servlet/src/main/java/ops/CutArgs.java index 2203c9c..d677c14 100644 --- a/data-access/servlet/src/main/java/ops/CutArgs.java +++ b/data-access/servlet/src/main/java/ops/CutArgs.java @@ -53,11 +53,11 @@ import vo.parameter.*; // FIXME or clla this Jdl.java ? class CutArgs { - static final Logger LOGGER = Logger.getLogger("CutArgs"); + static final Logger LOGGER = Logger.getLogger(CutArgs.class.getName()); static CutArgs[] parseCutArgsArr(String jsonString) { - LOGGER.info("trace : " + jsonString); + LOGGER.fine("trace : " + jsonString); List<CutArgs> argsList = new ArrayList<CutArgs>(); @@ -71,7 +71,7 @@ class CutArgs { // FIXME check type JSONObject jElem = (JSONObject) o; - LOGGER.info("jElem: " + jElem.toString()); + LOGGER.finest("jElem: " + jElem.toString()); CutArgs args = new CutArgs(); @@ -102,7 +102,7 @@ class CutArgs if(jCoord != null) { // legacy - LOGGER.info("TEST: " + jCoord.toString()); + LOGGER.finest("TEST: " + jCoord.toString()); args.lon = (Double) jCoord.get("l"); args.lat = (Double) jCoord.get("b"); diff --git a/data-access/servlet/src/main/java/ops/JdlMCutout.java b/data-access/servlet/src/main/java/ops/JdlMCutout.java index 4b24b11..a8f10b7 100644 --- a/data-access/servlet/src/main/java/ops/JdlMCutout.java +++ b/data-access/servlet/src/main/java/ops/JdlMCutout.java @@ -12,7 +12,7 @@ import org.json.simple.parser.ParseException; public class JdlMCutout { - static final Logger LOGGER = Logger.getLogger("JdlMCutout"); + static final Logger LOGGER = Logger.getLogger(JdlMCutout.class.getName()); /* used in mcutout to resolve pubdids to pathanme+hdunum */ @@ -137,9 +137,9 @@ public class JdlMCutout JSONArray jsonArray = (JSONArray)jsonObject.get("responses"); - LOGGER.info("jsonArray.size [responses]: " + jsonArray.size()); + LOGGER.finest("jsonArray.size [responses]: " + jsonArray.size()); //MCutResult.Cut[] cutResArr = new MCutResult.Cut[jsonArray.size()]; - //LOGGER.info("cutResArr.length[responses]: " + cutResArr.length); + //LOGGER.finest("cutResArr.length[responses]: " + cutResArr.length); ArrayList<MCutResult.Cut> cutResList = new ArrayList<MCutResult.Cut>(); @@ -148,7 +148,7 @@ public class JdlMCutout Iterator<JSONObject> itr = jsonArray.iterator(); while (itr.hasNext()) { - LOGGER.info("i: " + String.valueOf(i)); + LOGGER.finest("i: " + String.valueOf(i)); JSONObject jObj = itr.next(); MCutResult mc = new MCutResult(); @@ -172,7 +172,7 @@ public class JdlMCutout cuts.fileSize = fileSize; cuts.fileName = fileName; cuts.cutResArr = cutResList.toArray(new MCutResult.Cut[0]);//cutResArr; - LOGGER.info("cuts.cutResArr.length[responses]: " + cuts.cutResArr.length); + LOGGER.finest("cuts.cutResArr.length[responses]: " + cuts.cutResArr.length); } } catch (ParseException e) diff --git a/data-access/servlet/src/main/java/ops/Regrid.java b/data-access/servlet/src/main/java/ops/Regrid.java index 148c377..04ef066 100644 --- a/data-access/servlet/src/main/java/ops/Regrid.java +++ b/data-access/servlet/src/main/java/ops/Regrid.java @@ -4,7 +4,7 @@ // - merge : high level, which uses mergefiles after cutout import java.util.logging.Logger; -import java.util.logging.Level; +//import java.util.logging.Level; import java.io.IOException; import java.util.*; // ArrayList<String> @@ -64,9 +64,9 @@ class Regrid Vnaxis.add(nx); } catch (FitsException e) { - LOGGER.log(Level.SEVERE, "dimensions:",e); + LOGGER.severe("dimensions: " + e.getMessage()); } catch (IOException e) { - LOGGER.log(Level.SEVERE, "dimensions:",e); + LOGGER.severe("dimensions:" + e.getMessage()); } } // check that dimensions in all files match @@ -126,7 +126,7 @@ class Regrid // get card values as string (for exact match comparison to avoid string -> double conversion artifacts) // String allcardstr = f.getHDU(0).getHeader().findKey("CRVAL3"); // String cardvaluestr = f.getHDU(0).getHeader().findCard("CRVAL3").getValue(); - // LOGGER.info("CRVAL3 as string: " + cardvaluestr); + // LOGGER.finest("CRVAL3 as string: " + cardvaluestr); Vcrval.add(f.getHDU(0).getHeader().getDoubleValue("CRVAL3")); Vcrpix.add(f.getHDU(0).getHeader().getDoubleValue("CRPIX3")); @@ -135,16 +135,16 @@ class Regrid } catch (FitsException e) { - LOGGER.log(Level.SEVERE, "regrid_vel2:",e); + LOGGER.severe("regrid_vel2: " + e.getMessage()); } catch (IOException e) { - LOGGER.log(Level.SEVERE, "regrid_vel2:",e); + LOGGER.severe("regrid_vel2: " + e.getMessage()); } } /*/ debug print for( int ix = 0; ix < Vcrval.size() ; ix++ ) { - LOGGER.info(ix + + LOGGER.finest(ix + " " + Vcrval.get(ix) + " " + Vcdelt.get(ix) + " " + Vcrpix.get(ix) + @@ -161,7 +161,7 @@ class Regrid // max diff(CRVAL3) << absvalue(CDELT3) // long dnaxis = Collections.max(Vnaxis) - Collections.min(Vnaxis); - //LOGGER.info("dNAXIS : " + dnaxis); + //LOGGER.finest("dNAXIS : " + dnaxis); if( dnaxis != 0 ) { return false; } @@ -173,12 +173,12 @@ class Regrid // FIXME use exceptions instead... if(absavgCDELT == 0.0) { - LOGGER.warning("regrid: avg(CDELT3) == 0"); + LOGGER.finest("regrid: avg(CDELT3) == 0"); return false; } double dcdelt = java.lang.Math.abs(maxCDELT - minCDELT); - //LOGGER.info("dCDELT : " + dcdelt + //LOGGER.finest("dCDELT : " + dcdelt // + " ratio: " + // String.format("%.1f",100.0*dcdelt/absavgCDELT) // + " %" ); @@ -189,7 +189,7 @@ class Regrid double minCRVAL = Collections.min(Vcrval); double maxCRVAL = Collections.max(Vcrval); double dcrval = java.lang.Math.abs(maxCRVAL - minCRVAL); - //LOGGER.info("dCRVAL : " + dcrval + "|CDELT| : " + absavgCDELT + //LOGGER.finest("dCRVAL : " + dcrval + "|CDELT| : " + absavgCDELT // + " ratio: " + // String.format("%.1f",100.0*dcrval/absavgCDELT) // + " %" ); @@ -242,7 +242,7 @@ class Regrid } catch(Exception e) { // FIXME do error handling properly... - LOGGER.log(Level.SEVERE, "regrid_vel2:", e); + LOGGER.severe("regrid_vel2: " + e.getMessage()); } } diff --git a/data-access/servlet/src/main/java/ops/Reproject.java b/data-access/servlet/src/main/java/ops/Reproject.java index 4245798..0e1cb00 100644 --- a/data-access/servlet/src/main/java/ops/Reproject.java +++ b/data-access/servlet/src/main/java/ops/Reproject.java @@ -23,9 +23,9 @@ class Reproject implements Runnable public void run() { String name = Thread.currentThread().getName(); - VlkbAmqp.LOGGER.info("Start of " + name); + VlkbAmqp.LOGGER.fine("Start of " + name); response = datasets.mergefiles_reproject(id, prefix, fileName); - VlkbAmqp.LOGGER.info("End of " + name); + VlkbAmqp.LOGGER.fine("End of " + name); } } diff --git a/data-access/servlet/src/main/java/ops/SodaImpl.java b/data-access/servlet/src/main/java/ops/SodaImpl.java index 637c283..4c69b40 100644 --- a/data-access/servlet/src/main/java/ops/SodaImpl.java +++ b/data-access/servlet/src/main/java/ops/SodaImpl.java @@ -30,7 +30,7 @@ import vo.parameter.*; class SodaImpl implements Soda { - private static final Logger LOGGER = Logger.getLogger("SodaImpl"); + private static final Logger LOGGER = Logger.getLogger(SodaImpl.class.getName()); private static Settings.FITSPaths fitsPaths = null; private SodaImpl() {} @@ -38,7 +38,7 @@ class SodaImpl implements Soda public SodaImpl(Settings.FITSPaths fitsPaths) { - LOGGER.info("trace"); + LOGGER.fine("trace"); this.fitsPaths = fitsPaths; } @@ -47,6 +47,8 @@ class SodaImpl implements Soda Pos pos, Band band, Time time, Pol pol, String pixels, OutputStream outputStream) throws IOException, InterruptedException { + LOGGER.fine("trace"); + Instant start = Instant.now(); boolean has_overlap = false; @@ -67,7 +69,7 @@ class SodaImpl implements Soda jReq.add(time); jReq.add(pol); String coordString = jReq.toString(); - LOGGER.info("coordString: " + coordString); + LOGGER.finest("coordString: " + coordString); /* calc bounds */ @@ -79,7 +81,7 @@ class SodaImpl implements Soda ExecCmd execBounds = new ExecCmd(); execBounds.doRun(bos, cmdBounds); - LOGGER.info("execBounds exitValue: " + execBounds.exitValue); + LOGGER.finest("execBounds exitValue: " + execBounds.exitValue); boolean has_result = (execBounds.exitValue == 0); @@ -88,7 +90,7 @@ class SodaImpl implements Soda boundsString = new String(bos.toByteArray()); boundsString = replaceWithGrid(boundsString, pos, band, time, pol); - LOGGER.info("boundsString(with GRID): " + boundsString); + LOGGER.finest("boundsString(with GRID): " + boundsString); has_overlap = !((boundsString != null) && boundsString.trim().isEmpty()); @@ -101,7 +103,7 @@ class SodaImpl implements Soda bos.close(); Instant boundsDone = Instant.now(); - LOGGER.info("EXECTIME boundsDone: " + Duration.between(start, boundsDone)); + LOGGER.finer("EXECTIME boundsDone: " + Duration.between(start, boundsDone)); } if(has_overlap || pixels_valid) @@ -119,12 +121,12 @@ class SodaImpl implements Soda cmdCut[5] = fitsPaths.cutouts(); if(outputStream == null) - LOGGER.info("supplied outputStream for cut-file is null"); + LOGGER.finest("supplied outputStream for cut-file is null"); ExecCmd execCut = new ExecCmd(); execCut.doRun(outputStream, cmdCut); - LOGGER.info("execCut exitValue: " + execCut.exitValue); + LOGGER.finest("execCut exitValue: " + execCut.exitValue); boolean cut_successful = (execCut.exitValue == 0); @@ -134,7 +136,7 @@ class SodaImpl implements Soda } Instant cutDone = Instant.now(); - LOGGER.info("EXECTIME cutDone: " + Duration.between(start, cutDone)); + LOGGER.finer("EXECTIME cutDone: " + Duration.between(start, cutDone)); } else { @@ -146,6 +148,8 @@ class SodaImpl implements Soda private String genRegionForVlkbOverlapCmd(Pos pos, Band band) { + LOGGER.fine("trace"); + String region = ""; if(pos != null) @@ -171,7 +175,7 @@ class SodaImpl implements Soda } else { - LOGGER.info("FIXME here Exception: POLYGON not supported or pos.shape invalid: " + pos.shape); + LOGGER.finest("FIXME here Exception: POLYGON not supported or pos.shape invalid: " + pos.shape); } } @@ -194,12 +198,12 @@ class SodaImpl implements Soda // remove end-of-line (was added by vlkb_ast.cpp: cout << ... << endl) String lineSeparator = System.lineSeparator(); wcsBounds = wcsBounds.replace(lineSeparator, ""); - LOGGER.info("BOUNDS: " + wcsBounds); + LOGGER.finest("BOUNDS: " + wcsBounds); // replace in wcsBounds those bounds where pos,band,time or pol has system=GRID String[] substr = wcsBounds.split("(?=AXES)", 2); - for(String ss : substr) LOGGER.info("boundsResult: " + ss); + for(String ss : substr) LOGGER.finest("boundsResult: " + ss); String boundsString = substr[0]; boolean noOverlap = ((boundsString != null) && boundsString.trim().isEmpty()); @@ -213,12 +217,12 @@ class SodaImpl implements Soda if(substr.length > 1) { axesTypes = substr[1].replace("AXES"," ").trim(); - LOGGER.info("AXES TYPES: " + axesTypes); + LOGGER.finest("AXES TYPES: " + axesTypes); String[] bnds = normalize(boundsString); String[] types = normalize(axesTypes); // assert: bnds.length == types.length - LOGGER.info("boundsCount: " + bnds.length + " typesCount: " + types.length); + LOGGER.finest("boundsCount: " + bnds.length + " typesCount: " + types.length); if(bnds.length == types.length) boundsString = replaceBounds(bnds, types, pos, band); @@ -246,7 +250,7 @@ class SodaImpl implements Soda } } - LOGGER.info("replaced: " + String.join(" ", bnds)) ; + LOGGER.finest("replaced: " + String.join(" ", bnds)) ; return "[" + String.join(" ", bnds) + "]"; } @@ -256,7 +260,7 @@ class SodaImpl implements Soda private String[] normalize(String spaceStr) { String other = spaceStr.replace("[","").replace("]",""); - LOGGER.info("normalize: " + other); + LOGGER.finest("normalize: " + other); return other.split("\\s+"); } diff --git a/data-access/servlet/src/main/java/ops/VlkbAmqp.java b/data-access/servlet/src/main/java/ops/VlkbAmqp.java index 64af5a4..0184865 100644 --- a/data-access/servlet/src/main/java/ops/VlkbAmqp.java +++ b/data-access/servlet/src/main/java/ops/VlkbAmqp.java @@ -29,7 +29,7 @@ import vo.parameter.*; class VlkbAmqp implements Vlkb { - static final Logger LOGGER = Logger.getLogger("VlkbAmqp"); + static final Logger LOGGER = Logger.getLogger(VlkbAmqp.class.getName()); private Settings settings = null; private Subsurvey[] subsurveys = null; @@ -37,7 +37,7 @@ class VlkbAmqp implements Vlkb public VlkbAmqp() { - LOGGER.info("trace VlkbAmqp()"); + LOGGER.fine("trace VlkbAmqp()"); this.settings = Settings.getInstance(); this.resolver = (settings.dbConn.isDbUriEmpty() ? new ResolverFromId(subsurveys) : new ResolverByObsCore(settings.dbConn, subsurveys)); @@ -46,7 +46,7 @@ class VlkbAmqp implements Vlkb public VlkbAmqp(Settings settings) { - LOGGER.info("trace VlkbAmqp(settings)"); + LOGGER.fine("trace VlkbAmqp(settings)"); this.settings = settings; this.resolver = (settings.dbConn.isDbUriEmpty() ? new ResolverFromId(subsurveys) : new ResolverByObsCore(settings.dbConn, subsurveys)); @@ -56,7 +56,7 @@ class VlkbAmqp implements Vlkb public VlkbAmqp(Settings settings, Subsurvey[] subsurveys) { - LOGGER.info("trace VlkbAmqp(settings, subsurveys)"); + LOGGER.fine("trace VlkbAmqp(settings, subsurveys)"); this.settings = settings; this.subsurveys = subsurveys; this.resolver = (settings.dbConn.isDbUriEmpty() ? new ResolverFromId(subsurveys) @@ -69,7 +69,7 @@ class VlkbAmqp implements Vlkb public CutResult doMerge(String[] idArr, Coord coord, boolean countNullValues) throws FileNotFoundException, IOException { - LOGGER.info("trace"); + LOGGER.fine("trace"); return merge(idArr, coord, countNullValues); } @@ -82,11 +82,11 @@ class VlkbAmqp implements Vlkb boolean countNullValues, FitsCard[] extraCards) throws IOException, InterruptedException { - LOGGER.info("trace: " + pos.toString() ); + LOGGER.fine("trace: " + pos.toString() ); CutResult cutResult = new CutResult(); - LOGGER.info("Using AMQP"); + LOGGER.finer("Using AMQP"); JsonEncoder jReq = new JsonEncoder(); jReq.add(relPathname, hdunum); @@ -113,7 +113,7 @@ class VlkbAmqp implements Vlkb boolean countNullValues, Subsurvey[] subsurveys) throws IOException, InterruptedException { - LOGGER.info("trace"); + LOGGER.fine("trace"); FitsCard[] extraCards = null; @@ -128,7 +128,7 @@ class VlkbAmqp implements Vlkb } else { - LOGGER.info("Resolver returns subsurveyId null: no extraCards loaded."); + LOGGER.finer("Resolver returns subsurveyId null: no extraCards loaded."); } final String DEFAULT_TIME_SYSTEM = "MJD_UTC"; // FIXME take from confif file @@ -148,13 +148,13 @@ class VlkbAmqp implements Vlkb public MCutResult doMCutout(String jdlJson) throws IOException { - LOGGER.info("trace"); + LOGGER.fine("trace"); MCutResult mCutResult; - LOGGER.info("doMCutout over AMQP"); + LOGGER.finer("doMCutout over AMQP"); String updatedJsonString = JdlMCutout.resolveAndUpdateJsonRequest(jdlJson, settings, subsurveys); - LOGGER.info("doMCutout over AMQP : " + updatedJsonString); + LOGGER.finest("doMCutout over AMQP : " + updatedJsonString); String outJson = RpcOverAmqp.doRpc(settings.amqpConn, JdlMCutout.mcutoutToJson(updatedJsonString) ); mCutResult = JdlMCutout.responseFromMCutoutJson(outJson); @@ -199,9 +199,9 @@ class VlkbAmqp implements Vlkb //Subsurvey.subsurveysFindCards(subsurveys, rsl.obsCollection());//rsl.subsurveyId); String absSubimgPathname = settings.fitsPaths.cutouts() + "/" + generateSubimgPathname(rsl.relPathname(), rsl.hdunum()); - LOGGER.info("absSubimgPathname: " + absSubimgPathname); + LOGGER.finest("absSubimgPathname: " + absSubimgPathname); - LOGGER.info("Using AMQP"); + LOGGER.finer("Using AMQP"); JsonEncoder jReq = new JsonEncoder(); jReq.add(rsl.relPathname(), rsl.hdunum()); @@ -223,7 +223,7 @@ class VlkbAmqp implements Vlkb protected CutResult merge(String[] pubdids, Coord coord, Boolean countNullValues) { - LOGGER.info("trace"); + LOGGER.fine("trace"); ArrayList<CutResult> allresults = new ArrayList<CutResult>(); @@ -256,7 +256,7 @@ class VlkbAmqp implements Vlkb Boolean changed = grid.regrid_vel2(allCutPathnames); if(changed){ //allresults.add("MSG Keywords CDELT3, CRVAL3 were adjusted for merge regridding."); - LOGGER.info("MSG Keywords CDELT3, CRVAL3 were adjusted for merge regridding."); + LOGGER.finer("MSG Keywords CDELT3, CRVAL3 were adjusted for merge regridding."); } } @@ -308,7 +308,7 @@ class VlkbAmqp implements Vlkb String prefix, // IN prefix added after filename-start-word String[] filestomerge) // IN abs path with filenames to be merged { - LOGGER.info("trace"); + LOGGER.fine("trace"); String InJson = JsonEncoderMerge.mergefilesToJson( prefix, filestomerge); String OutJson = RpcOverAmqp.doRpc(settings.amqpConn, InJson); @@ -325,10 +325,10 @@ class VlkbAmqp implements Vlkb String prefix, // IN prefix added after filename-start-word String[] filestomerge) // IN abs path with filenames to be merged { - LOGGER.info("mergefiles_parallel()"); + LOGGER.fine("trace"); String[] responseCH = mergefiles_common_header(jobId, logfilename, prefix, filestomerge); - for(String sentence : responseCH) VlkbAmqp.LOGGER.info("responseCmnHdr: " + sentence); + for(String sentence : responseCH) VlkbAmqp.LOGGER.finest("responseCmnHdr: " + sentence); // check if response errored -> abort with 500: Internal Server Error & log details int threadsCount = filestomerge.length; @@ -360,7 +360,7 @@ class VlkbAmqp implements Vlkb } - for(String sentence : reprojectArr[i].response) VlkbAmqp.LOGGER.info("response[" + String.valueOf(i) + "]: " + sentence); + for(String sentence : reprojectArr[i].response) VlkbAmqp.LOGGER.finest("response[" + String.valueOf(i) + "]: " + sentence); if(!isResponseOk(reprojectArr[i].response)) { ;// FIXME response incorrect -> abort merge-job, free resources @@ -391,7 +391,7 @@ class VlkbAmqp implements Vlkb String prefix, // IN prefix added after filename-start-word String[] filestomerge) // IN abs path with filenames to be merged { - LOGGER.info("mergefiles_split_execution()"); + LOGGER.fine("trace"); String[] responseCH = mergefiles_common_header(jobId, logfilename, prefix, filestomerge); // check if response errored -> abort with 500: Internal Server Error & log details @@ -414,7 +414,7 @@ class VlkbAmqp implements Vlkb String prefix, // IN prefix added after filename-start-word String[] filestomerge) // IN abs path with filenames to be merged { - LOGGER.info("trace"); + LOGGER.fine("trace"); String InJson = JsonEncoderMerge.mergefilesCommonHeaderToJson(jobId, prefix, filestomerge); String OutJson = RpcOverAmqp.doRpc(settings.amqpConn, InJson); @@ -429,7 +429,7 @@ class VlkbAmqp implements Vlkb String prefix, // IN prefix added after filename-start-word String fitsfilename) // IN logfilename without path { - LOGGER.info("trace"); + LOGGER.fine("trace"); String InJson = JsonEncoderMerge.mergefilesReprojectToJson(jobId, prefix, fitsfilename); String OutJson = RpcOverAmqp.doRpc(settings.amqpConn, InJson); @@ -443,7 +443,7 @@ class VlkbAmqp implements Vlkb String jobId, // IN jobId to distinguish parallel executed requests String prefix) // IN prefix added after filename-start-word { - LOGGER.info("trace"); + LOGGER.fine("trace"); String InJson = JsonEncoderMerge.mergefilesAddReprojectedToJson(jobId, prefix); String OutJson = RpcOverAmqp.doRpc(settings.amqpConn, InJson); @@ -462,7 +462,7 @@ class VlkbAmqp implements Vlkb // -- from cutout: the cutout filename (server local) private String[] selectCutPathnames(CutResult[] results) { - LOGGER.info("selectCutPathnames()"); + LOGGER.fine("trace"); // return only data (without MSG's LOG's etc) ArrayList<String> data = new ArrayList<String>(); @@ -470,7 +470,7 @@ class VlkbAmqp implements Vlkb // sanity check - move after doFunc call (here covered by exception) // FIXME consider catch null-pointer-exception if(results == null) { - LOGGER.info("selectCutPathnames: results-table is null."); + LOGGER.finest("selectCutPathnames: results-table is null."); return null; } @@ -489,8 +489,8 @@ class VlkbAmqp implements Vlkb String localfname = res.substring(4);//.replaceAll(FITScutpath, ""); String[] ssfn = localfname.split(":"); //String[] ssfn = localfname.substring(4).split(":"); - LOGGER.info("ssfn[0]: " + ssfn[0]); - LOGGER.info("ssfn[1]: " + ssfn[1]); + LOGGER.finest("ssfn[0]: " + ssfn[0]); + LOGGER.finest("ssfn[1]: " + ssfn[1]); data.add(ssfn[1]); //data.add(localfname); break; diff --git a/data-access/servlet/src/main/java/ops/VlkbCli.java b/data-access/servlet/src/main/java/ops/VlkbCli.java index f49b229..f10ff25 100644 --- a/data-access/servlet/src/main/java/ops/VlkbCli.java +++ b/data-access/servlet/src/main/java/ops/VlkbCli.java @@ -39,7 +39,7 @@ import vo.parameter.*; class VlkbCli implements Vlkb { - static final Logger LOGGER = Logger.getLogger("VlkbCli"); + static final Logger LOGGER = Logger.getLogger(VlkbCli.class.getName()); private Settings settings = null; private Subsurvey[] subsurveys = null; @@ -49,7 +49,7 @@ class VlkbCli implements Vlkb public VlkbCli() { - LOGGER.info("trace VlkbCli()"); + LOGGER.fine("trace VlkbCli()"); this.settings = Settings.getInstance(); this.soda = new SodaImpl(settings.fitsPaths); this.resolver = (settings.dbConn.isDbUriEmpty() ? new ResolverFromId(subsurveys) @@ -59,7 +59,7 @@ class VlkbCli implements Vlkb public VlkbCli(Settings settings) { - LOGGER.info("trace VlkbCli(settings)"); + LOGGER.fine("trace VlkbCli(settings)"); this.settings = settings; this.soda = new SodaImpl(settings.fitsPaths); this.resolver = (settings.dbConn.isDbUriEmpty() ? new ResolverFromId(subsurveys) @@ -69,7 +69,7 @@ class VlkbCli implements Vlkb public VlkbCli(Settings settings, Subsurvey[] subsurveys) { - LOGGER.info("trace VlkbCli(settings, subsurveys)"); + LOGGER.fine("trace VlkbCli(settings, subsurveys)"); this.settings = settings; this.subsurveys = subsurveys; this.soda = new SodaImpl(settings.fitsPaths); @@ -82,7 +82,7 @@ class VlkbCli implements Vlkb public CutResult doMerge(String[] idArr, Coord coord, boolean countNullValues) throws FileNotFoundException, IOException { - LOGGER.info("trace doMerge by CLI is NOT IMPLEMENTED (only by AMQP)"); + LOGGER.fine("trace doMerge by CLI is NOT IMPLEMENTED (only by AMQP)"); return new CutResult(); } @@ -94,16 +94,16 @@ class VlkbCli implements Vlkb boolean countNullValues, FitsCard[] extraCards) throws IOException, InterruptedException { - LOGGER.info("trace: " + pos.toString() ); + LOGGER.fine("trace: " + pos.toString() ); CutResult cutResult = new CutResult(); - LOGGER.info("Using doStream() to local file"); + LOGGER.finer("Using doStream() to local file"); String absSubimgPathname = settings.fitsPaths.cutouts() + "/" + generateSubimgPathname(relPathname, hdunum); - LOGGER.info("Uses local filename : " + absSubimgPathname); + LOGGER.finer("Uses local filename : " + absSubimgPathname); OutputStream fileOutputStream = new FileOutputStream( new File(absSubimgPathname) ); @@ -120,7 +120,7 @@ class VlkbCli implements Vlkb if(extraCards == null || (extraCards.length < 1)) { - LOGGER.info("Adding extraCards to cut-file implemented only in VlkbAmql"); + LOGGER.finer("Adding extraCards to cut-file implemented only in VlkbAmql"); } cutResult.pixels = null; @@ -143,7 +143,7 @@ class VlkbCli implements Vlkb ExecCmd exec = new ExecCmd(); exec.doRun(bos, cmdBounds); - LOGGER.info("exec NullVals exitValue: " + exec.exitValue); + LOGGER.finest("exec NullVals exitValue: " + exec.exitValue); bos.close(); @@ -151,7 +151,7 @@ class VlkbCli implements Vlkb if(hasResult) { String nullValsString = new String(bos.toByteArray()); - LOGGER.info("vlkb nullvals: " + nullValsString); + LOGGER.finest("vlkb nullvals: " + nullValsString); if((nullValsString != null) && nullValsString.trim().isEmpty()) { @@ -183,7 +183,7 @@ class VlkbCli implements Vlkb boolean countNullValues/*, Subsurvey[] subsurveys*/) throws IOException, InterruptedException { - LOGGER.info("trace"); + LOGGER.fine("trace"); FitsCard[] extraCards = null; @@ -198,7 +198,7 @@ class VlkbCli implements Vlkb } else { - LOGGER.info("Resolver returns subsurveyId null: no extraCards loaded."); + LOGGER.finer("Resolver returns subsurveyId null: no extraCards loaded."); } final String DEFAULT_TIME_SYSTEM = "MJD_UTC"; // FIXME take from confif file @@ -237,7 +237,7 @@ class VlkbCli implements Vlkb public MCutResult doMCutout(String jdlJson) throws IOException, InterruptedException { - LOGGER.info("trace"); + LOGGER.fine("trace"); MCutResult mCutResult; @@ -253,7 +253,7 @@ class VlkbCli implements Vlkb private MCutResult.Cut[] doCutouts(CutArgs[] cutArgsArr) { - LOGGER.info("trace, count of cuts : " + String.valueOf( cutArgsArr.length ) ); + LOGGER.fine("trace, count of cuts : " + String.valueOf( cutArgsArr.length ) ); List<MCutResult.Cut> cutResList = new ArrayList<MCutResult.Cut>(); @@ -266,7 +266,7 @@ class VlkbCli implements Vlkb cut.index = ix++; - LOGGER.info("cut" + String.valueOf(cut.index) + " : " + cut.content); + LOGGER.finest("cut" + String.valueOf(cut.index) + " : " + cut.content); cutResList.add(cut); } @@ -297,7 +297,7 @@ class VlkbCli implements Vlkb for(MCutResult.Cut cut : cutArr) { - LOGGER.info("cut-id"+ String.valueOf(cut.index) + " -> " + cut.content); + LOGGER.finest("cut-id"+ String.valueOf(cut.index) + " -> " + cut.content); if(cut.contentType == MCutResult.Cut.ContentType.FILENAME) { Path p = Paths.get(cut.content); @@ -336,7 +336,7 @@ class VlkbCli implements Vlkb private MCutResult.Cut doFileByIdWithErr(String id, Pos pos, Band band, Time time, Pol pol, String pixels, boolean countNullValues/*, Subsurvey[] subsurveys*/) { - LOGGER.info("trace"); + LOGGER.fine("trace"); MCutResult mCutResult = new MCutResult(); MCutResult.Cut cut = mCutResult.new Cut(/* FIXME eventually add here new Inputs(id, pos,..) */); @@ -354,19 +354,19 @@ class VlkbCli implements Vlkb { cut.content = "MultiValuedParamNotSupported: " + ex.getMessage(); cut.contentType = MCutResult.Cut.ContentType.BAD_REQUEST; - LOGGER.info(cut.content); + LOGGER.warning(cut.content); } catch(IllegalArgumentException ex) { cut.content = "IllegalArgumentException: " + ex.getMessage(); cut.contentType = MCutResult.Cut.ContentType.BAD_REQUEST; - LOGGER.info(cut.content); + LOGGER.warning(cut.content); } catch(Exception ex) { cut.content = "Exception: " + ex.getMessage(); cut.contentType = MCutResult.Cut.ContentType.SERVICE_ERROR; - LOGGER.info(cut.content); + LOGGER.severe(cut.content); ex.printStackTrace(); } diff --git a/data-access/servlet/src/main/java/ops/amqp/JsonDecoder.java b/data-access/servlet/src/main/java/ops/amqp/JsonDecoder.java index 93263e8..cfc3b72 100644 --- a/data-access/servlet/src/main/java/ops/amqp/JsonDecoder.java +++ b/data-access/servlet/src/main/java/ops/amqp/JsonDecoder.java @@ -31,7 +31,7 @@ import org.json.simple.parser.ParseException; public class JsonDecoder { - static final Logger LOGGER = Logger.getLogger("JsonDecoder"); + static final Logger LOGGER = Logger.getLogger(JsonDecoder.class.getName()); public static CutResult responseFromCutoutJson(String response) // throws ParseException @@ -77,7 +77,7 @@ public class JsonDecoder } catch (ParseException e) { - LOGGER.info(e.getMessage()); + LOGGER.severe(e.getMessage()); e.printStackTrace(); throw new IllegalStateException("Internal system error."); } diff --git a/data-access/servlet/src/main/java/ops/amqp/JsonEncoder.java b/data-access/servlet/src/main/java/ops/amqp/JsonEncoder.java index 0891848..52a8a43 100644 --- a/data-access/servlet/src/main/java/ops/amqp/JsonEncoder.java +++ b/data-access/servlet/src/main/java/ops/amqp/JsonEncoder.java @@ -12,7 +12,7 @@ import vo.parameter.*; public class JsonEncoder { - static final Logger LOGGER = Logger.getLogger("JsonEncoder"); + static final Logger LOGGER = Logger.getLogger(JsonEncoder.class.getName()); private JSONObject obj; @@ -23,8 +23,6 @@ public class JsonEncoder public void add(String pathname, int hdunum) { - LOGGER.info("trace" + pathname); - this.obj.put("img_pathname", pathname); this.obj.put("img_hdunum", hdunum); } @@ -35,6 +33,8 @@ public class JsonEncoder public void add(Pos pos) { + LOGGER.fine("trace"); + if(pos != null) { JSONObject j = new JSONObject(); diff --git a/data-access/servlet/src/main/java/ops/amqp/RpcOverAmqp.java b/data-access/servlet/src/main/java/ops/amqp/RpcOverAmqp.java index ff4068e..8aa1b1a 100644 --- a/data-access/servlet/src/main/java/ops/amqp/RpcOverAmqp.java +++ b/data-access/servlet/src/main/java/ops/amqp/RpcOverAmqp.java @@ -25,7 +25,7 @@ import java.util.UUID; public class RpcOverAmqp { - private static final Logger LOGGER = Logger.getLogger("RpcOverAmqp"); + private static final Logger LOGGER = Logger.getLogger(RpcOverAmqp.class.getName()); private final boolean NO_ACK = true; // affects message consume from queue: @@ -48,6 +48,8 @@ public class RpcOverAmqp public static String doRpc(Settings.AmqpConn amqpConn, String InStr) { + LOGGER.fine("trace"); + final String userName = "guest"; final String password = "guest"; // FIXME move these to Settings @@ -64,13 +66,13 @@ public class RpcOverAmqp try { - LOGGER.info("Sent request : " + InStr); + LOGGER.finer("Sent request : " + InStr); OutStr = rpc.callAndWaitReply(InStr); - LOGGER.info("Got response : " + OutStr); + LOGGER.finer("Got response : " + OutStr); } catch (Exception e) { - e.printStackTrace(); + LOGGER.severe("Exception: " + e.getMessage()); } finally { @@ -80,7 +82,7 @@ public class RpcOverAmqp } catch (Exception ignore) { - LOGGER.info("ignoring exception on rpc.close():" + ignore.getMessage()); + LOGGER.finer("ignoring exception on rpc.close():" + ignore.getMessage()); } } @@ -122,7 +124,7 @@ public class RpcOverAmqp } catch(Exception e) { - e.printStackTrace(); + LOGGER.severe("Exception: " + e.getMessage()); } } @@ -150,7 +152,7 @@ public class RpcOverAmqp QueueingConsumer.Delivery delivery = consumer.nextDelivery(); - System.out.println("CorrId sent[" + channelNumber + "]: " + delivery.getProperties().getCorrelationId() + LOGGER.finest("CorrId sent[" + channelNumber + "]: " + delivery.getProperties().getCorrelationId() + "\nCorrId recv: " + corrId + "\nreplyQueueName: " + replyQueueName); diff --git a/data-access/servlet/src/main/java/ops/cli/ExecCmd.java b/data-access/servlet/src/main/java/ops/cli/ExecCmd.java index 43f7692..cee6e77 100644 --- a/data-access/servlet/src/main/java/ops/cli/ExecCmd.java +++ b/data-access/servlet/src/main/java/ops/cli/ExecCmd.java @@ -6,7 +6,7 @@ import java.io.*; class StreamGobbler extends Thread { - public static final Logger LOGGER = Logger.getLogger("StreamGobbler"); + public static final Logger LOGGER = Logger.getLogger(StreamGobbler.class.getName()); InputStream is; String type; @@ -19,6 +19,7 @@ class StreamGobbler extends Thread StreamGobbler(InputStream is, String type, OutputStream redirect) { + LOGGER.fine("trace"); this.is = is; this.type = type; this.os = redirect; @@ -27,6 +28,8 @@ class StreamGobbler extends Thread public void run() { + LOGGER.fine("trace"); + try { BufferedOutputStream bos = null; @@ -45,7 +48,7 @@ class StreamGobbler extends Thread } else { - LOGGER.info(type + ">" + new String(buffer, 0, nread, "utf-8")); + LOGGER.finest(type + ">" + new String(buffer, 0, nread, "utf-8")); } } @@ -62,16 +65,16 @@ class StreamGobbler extends Thread class ExecCmd { - public static final Logger LOGGER = Logger.getLogger("ExecCmd"); + public static final Logger LOGGER = Logger.getLogger(ExecCmd.class.getName()); public int exitValue; public void doRun(OutputStream outputStream, String[] cmd) throws IOException, InterruptedException { - // Assert outputStream != null + LOGGER.fine("trace CMD: " + Arrays.toString(cmd)); - LOGGER.info("CMD: " + Arrays.toString(cmd)); + // Assert outputStream != null long start_nsec = System.nanoTime(); @@ -103,7 +106,7 @@ class ExecCmd long meas4_nsec = System.nanoTime(); - LOGGER.info("RUNTIME[nsec] ExecCmd::doRun(): " + LOGGER.finer("RUNTIME[nsec] ExecCmd::doRun(): " + String.valueOf((long)Math.round( (meas1_nsec - start_nsec)/1.0e6 )) + " " + String.valueOf((long)Math.round( (meas2_nsec - start_nsec)/1.0e6 )) + " " + String.valueOf((long)Math.round( (meas3_nsec - start_nsec)/1.0e6 )) diff --git a/data-access/servlet/src/main/java/resolver/ResolverByObsCore.java b/data-access/servlet/src/main/java/resolver/ResolverByObsCore.java index b2a101d..d2490f2 100644 --- a/data-access/servlet/src/main/java/resolver/ResolverByObsCore.java +++ b/data-access/servlet/src/main/java/resolver/ResolverByObsCore.java @@ -30,25 +30,25 @@ class ResolverByObsCore implements Resolver public void resolve(String pubdid) { - LOGGER.info("trace " + pubdid); + LOGGER.fine("trace " + pubdid); try { resolveByMapping(pubdid, dbConn); } catch(ClassNotFoundException e) { - LOGGER.info("DB driver class was not loaded. No database connection."); + LOGGER.severe("DB driver class was not loaded. No database connection."); } - LOGGER.info("relPathname : " + relPathname); - LOGGER.info("hdunum : " + String.valueOf(hdunum)); - LOGGER.info("obsCollection : " + this.subsurveyId); + LOGGER.finer("relPathname : " + relPathname); + LOGGER.finer("hdunum : " + String.valueOf(hdunum)); + LOGGER.finer("obsCollection : " + this.subsurveyId); } private void resolveByMapping(String pubdid, Settings.DBConn dbConn) throws ClassNotFoundException { - LOGGER.info("trace " + pubdid); + LOGGER.fine("trace " + pubdid); if(this.subsurveys == null) { @@ -102,7 +102,7 @@ class ResolverByObsCore implements Resolver private void db_queryAccessUrlAndObsCollection(Settings.DBConn dbConn, String pubdid)//, String accessUrl, String obsCollection) throws ClassNotFoundException { - LOGGER.info("trace"); + LOGGER.fine("trace"); ResolverByObsCoreDb rdb; synchronized(ResolverByObsCoreDb.class) diff --git a/data-access/servlet/src/main/java/resolver/ResolverByObsCoreDb.java b/data-access/servlet/src/main/java/resolver/ResolverByObsCoreDb.java index 5f80c98..57847af 100644 --- a/data-access/servlet/src/main/java/resolver/ResolverByObsCoreDb.java +++ b/data-access/servlet/src/main/java/resolver/ResolverByObsCoreDb.java @@ -43,7 +43,7 @@ public class ResolverByObsCoreDb conn = null; st = null; res = null; - //LOGGER.info("Loading DB driver: " + DB_DRIVER); + //LOGGER.finer("Loading DB driver: " + DB_DRIVER); //Class.forName(DB_DRIVER); } @@ -54,11 +54,11 @@ public class ResolverByObsCoreDb String TheQuery = "SELECT access_url,obs_collection FROM obscore " + "WHERE obs_publisher_did = \'"+ obsPubdid +"\'"; - LOGGER.info(TheQuery); + LOGGER.finest(TheQuery); String[] results = new String[2]; - LOGGER.info("Connecting to: " + dbconn.uri() + " with optional user/pwd: " + dbconn.userName() + " / " + dbconn.password() ); + LOGGER.finer("Connecting to: " + dbconn.uri() + " with optional user/pwd: " + dbconn.userName() + " / " + dbconn.password() ); try( Connection conn = DriverManager.getConnection(dbconn.uri(), dbconn.userName(), dbconn.password()); @@ -69,7 +69,7 @@ public class ResolverByObsCoreDb if(res == null) { - LOGGER.info("Pubdid not in the db: " + pubdid); + LOGGER.finest("Pubdid not in the db: " + pubdid); return null; }; @@ -91,7 +91,7 @@ public class ResolverByObsCoreDb } /* catch (ClassNotFoundException e) { - LOGGER.info("DB driver "+ DB_DRIVER +" not found: " + e.getMessage()); + LOGGER.severe("DB driver "+ DB_DRIVER +" not found: " + e.getMessage()); e.printStackTrace(); } finally @@ -121,12 +121,12 @@ public class ResolverByObsCoreDb private void logSqlExInfo(SQLException se) { - LOGGER.info("SQLState : " + se.getSQLState()); - LOGGER.info("ErrorCode: " + se.getErrorCode()); - LOGGER.info("Message : " + se.getMessage()); + LOGGER.finer("SQLState : " + se.getSQLState()); + LOGGER.finer("ErrorCode: " + se.getErrorCode()); + LOGGER.finer("Message : " + se.getMessage()); Throwable t = se.getCause(); while(t != null) { - LOGGER.info("Cause: " + t); + LOGGER.finer("Cause: " + t); t = t.getCause(); } } @@ -143,11 +143,11 @@ public class ResolverByObsCoreDb // Class.forName(DB_DRIVER); /* OR * DriverManager.registerDriver(new org.postgresql.Driver()); - * LOGGER.info(getClasspathString()); - * LOGGER.info(getRegisteredDriverList()); + * LOGGER.finest(getClasspathString()); + * LOGGER.finest(getRegisteredDriverList()); * / - LOGGER.info("Connecting to: " + dbconn.uri() + " with optional user/pwd: " + dbconn.userName() + " / " + dbconn.password() ); + LOGGER.finer("Connecting to: " + dbconn.uri() + " with optional user/pwd: " + dbconn.userName() + " / " + dbconn.password() ); // Connection conn = DriverManager.getConnection(dbconn.uri(), dbconn.userName(), dbconn.password()); diff --git a/data-access/servlet/src/main/java/resolver/ResolverFromId.java b/data-access/servlet/src/main/java/resolver/ResolverFromId.java index 95ee9ec..847aa6a 100644 --- a/data-access/servlet/src/main/java/resolver/ResolverFromId.java +++ b/data-access/servlet/src/main/java/resolver/ResolverFromId.java @@ -25,7 +25,7 @@ class ResolverFromId implements Resolver public void resolve(String pubdid) { - LOGGER.info("trace " + pubdid); + LOGGER.fine("trace " + pubdid); boolean isIvoid = pubdid.substring(0,6).equals("ivo://"); @@ -35,9 +35,9 @@ class ResolverFromId implements Resolver // FIXME resolve subsurveyId by matching relPathname to subsurveys::storage-path & file-filter - LOGGER.info("relPathname : " + relPathname); - LOGGER.info("hdunum : " + String.valueOf(hdunum)); - LOGGER.info("subsurveyId : " + ((subsurveyId == null) ? "null" : this.subsurveyId) ); + LOGGER.finer("relPathname : " + relPathname); + LOGGER.finer("hdunum : " + String.valueOf(hdunum)); + LOGGER.finer("subsurveyId : " + ((subsurveyId == null) ? "null" : this.subsurveyId) ); } else { @@ -49,7 +49,7 @@ class ResolverFromId implements Resolver private void resolveIvoid(String pubdid) { - LOGGER.info("trace " + pubdid); + LOGGER.fine("trace " + pubdid); int qmarkIx = pubdid.lastIndexOf("?"); int dhashIx = pubdid.lastIndexOf("#");// returns -1 if hash not found diff --git a/data-access/servlet/src/main/java/webapi/AuthZFilter.java b/data-access/servlet/src/main/java/webapi/AuthZFilter.java index c2b94e1..d24628f 100644 --- a/data-access/servlet/src/main/java/webapi/AuthZFilter.java +++ b/data-access/servlet/src/main/java/webapi/AuthZFilter.java @@ -37,7 +37,7 @@ import java.io.ByteArrayOutputStream; class AuthZ { - private static final Logger LOGGER = Logger.getLogger("AuthZ"); + private static final Logger LOGGER = Logger.getLogger(AuthZ.class.getName()); private static final AuthZSettings settings = AuthZSettings.getInstance("authpolicy.properties"); List<String> pubdidList = new ArrayList<String>(); @@ -47,7 +47,7 @@ class AuthZ public AuthZ(HttpServletRequest req) throws IOException, ServletException { - LOGGER.info("constructor"); + LOGGER.fine("constructor"); String[] pubdidArr = req.getParameterValues("ID"); if(pubdidArr == null) @@ -61,7 +61,7 @@ class AuthZ for(String pubdid : pubdidArr) if(pubdid.length() > 0) pubdidList.add(pubdid); - LOGGER.info("pubdids: " + String.join(" ", pubdidList)); + LOGGER.finest("pubdids: " + String.join(" ", pubdidList)); } } @@ -82,7 +82,7 @@ class AuthZ public boolean isAuthorized(HttpServletRequest req) { - LOGGER.info("isAuthorized"); + LOGGER.fine("isAuthorized"); AuthPolicy auth = null; try @@ -113,7 +113,7 @@ class AuthZ @javax.servlet.annotation.MultipartConfig public class AuthZFilter implements Filter { - private static final Logger LOGGER = Logger.getLogger("AuthZFilter"); + private static final Logger LOGGER = Logger.getLogger(AuthZFilter.class.getName()); @Override @@ -125,7 +125,7 @@ public class AuthZFilter implements Filter @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { - LOGGER.info("doFilter"); + LOGGER.fine("doFilter"); HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse resp = (HttpServletResponse) response; diff --git a/data-access/servlet/src/main/java/webapi/AuthZSettings.java b/data-access/servlet/src/main/java/webapi/AuthZSettings.java index 7cd7e6a..ecb811e 100644 --- a/data-access/servlet/src/main/java/webapi/AuthZSettings.java +++ b/data-access/servlet/src/main/java/webapi/AuthZSettings.java @@ -9,7 +9,7 @@ import java.io.PrintWriter; class AuthZSettings { - private static final Logger LOGGER = Logger.getLogger("AuthZSettings"); + private static final Logger LOGGER = Logger.getLogger(AuthZSettings.class.getName()); public static class DBConn { @@ -36,6 +36,8 @@ class AuthZSettings // no reasonable code-defaults can be invented public static AuthZSettings getInstance(String propertiesFilename) { + LOGGER.config("reading settings from : " + propertiesFilename); + try { InputStream ins = @@ -72,6 +74,8 @@ class AuthZSettings private static DBConn loadDBConn(Properties properties) { + LOGGER.fine("trace"); + DBConn dbconn = new AuthZSettings.DBConn(); dbconn.uri = properties.getProperty("db_uri", "jdbc:postgresql://localhost:5432/vialactea").strip(); dbconn.schema = properties.getProperty("db_schema", "datasets").strip(); diff --git a/data-access/servlet/src/main/java/webapi/ServletCutout.java b/data-access/servlet/src/main/java/webapi/ServletCutout.java index c2ad072..4591099 100644 --- a/data-access/servlet/src/main/java/webapi/ServletCutout.java +++ b/data-access/servlet/src/main/java/webapi/ServletCutout.java @@ -1,5 +1,6 @@ import java.util.logging.Logger; +import java.util.logging.Level; import java.security.Principal; @@ -46,7 +47,7 @@ import vo.parameter.*; public class ServletCutout extends HttpServlet { - protected static final Logger LOGGER = Logger.getLogger("ServletCutout"); + protected static final Logger LOGGER = Logger.getLogger(ServletCutout.class.getName()); protected static final Settings settings = Settings.getInstance(); protected static final Subsurvey[] subsurveys = Subsurvey.loadSubsurveys(settings.fitsPaths.surveysMetadataAbsPathname()); @@ -61,15 +62,15 @@ public class ServletCutout extends HttpServlet public void init() throws ServletException { - LOGGER.info("FITS : " + settings.fitsPaths.toString()); + LOGGER.config("FITS : " + settings.fitsPaths.toString()); if(subsurveys != null) - LOGGER.info("Subsurveys loaded : " + String.valueOf(subsurveys.length)); - LOGGER.info("DEFAULT SKY/SPEC/TIME SYSTEM : " + DEFAULT_SKY_SYSTEM + " / " + DEFAULT_SPEC_SYSTEM + " / " + DEFAULT_TIME_SYSTEM); - LOGGER.info("DEFAULT_RESPONSEFORMAT : " + DEFAULT_RESPONSEFORMAT); - LOGGER.info("Resolver : " + (resolveFromId ? "IVOID" : "DB")); - LOGGER.info("Engine : " + (useEngineOverCli ? "CLI" : "AMQP")); + LOGGER.config("Subsurveys loaded : " + String.valueOf(subsurveys.length)); + LOGGER.config("DEFAULT SKY/SPEC/TIME SYSTEM : " + DEFAULT_SKY_SYSTEM + " / " + DEFAULT_SPEC_SYSTEM + " / " + DEFAULT_TIME_SYSTEM); + LOGGER.config("DEFAULT_RESPONSEFORMAT : " + DEFAULT_RESPONSEFORMAT); + LOGGER.config("Resolver : " + (resolveFromId ? "IVOID" : "DB")); + LOGGER.config("Engine : " + (useEngineOverCli ? "CLI" : "AMQP")); if(!useEngineOverCli) - LOGGER.info("AMQP : " + settings.amqpConn.toString()); + LOGGER.config("AMQP : " + settings.amqpConn.toString()); } @@ -120,7 +121,7 @@ public class ServletCutout extends HttpServlet protected void doCutoutStream(String id, Pos pos, Band band, Time time, Pol pol, String pixels, OutputStream respOutputStream) throws IOException, InterruptedException { - LOGGER.info("trace" + pos); + LOGGER.fine("trace " + pos); final Resolver resolver = (resolveFromId ? new ResolverFromId(subsurveys) : @@ -138,7 +139,7 @@ public class ServletCutout extends HttpServlet boolean countNullValues) throws IOException, InterruptedException { - LOGGER.info("trace"); + LOGGER.fine("trace"); FitsCard[] extraCards = null; @@ -158,7 +159,7 @@ public class ServletCutout extends HttpServlet } else { - LOGGER.info("Resolver returns subsurveyId null: no extraCards loaded."); + LOGGER.fine("Resolver returns subsurveyId null: no extraCards loaded."); } return vlkb.doFile(resolver.relPathname(), resolver.hdunum(), @@ -191,19 +192,19 @@ public class ServletCutout extends HttpServlet protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException, UnsupportedEncodingException { - final boolean NO_QUERY_STRING = (request.getQueryString() == null); if(NO_QUERY_STRING) { writeSodaDescriptor(request, response); - LOGGER.info("normal exit with SODA service descriptor"); + LOGGER.fine("normal exit with SODA service descriptor"); return; } else { + LOGGER.info(URLDecoder.decode(request.getQueryString(), "UTF-8")); execRequest(request, response); - LOGGER.info("normal exit"); + LOGGER.fine("normal exit"); } } @@ -215,13 +216,14 @@ public class ServletCutout extends HttpServlet if(NO_QUERY_STRING) { writeSodaDescriptor(request, response); - LOGGER.info("normal exit with SODA service descriptor"); + LOGGER.fine("normal exit with SODA service descriptor"); return; } else { + LOGGER.info(URLDecoder.decode(request.getQueryString(), "UTF-8")); execRequest(request, response); - LOGGER.info("normal exit"); + LOGGER.fine("normal exit"); } } @@ -261,7 +263,7 @@ public class ServletCutout extends HttpServlet String respFormat = sodaReq_getResponseFormat(request, DEFAULT_RESPONSEFORMAT); - LOGGER.info("responseFormat: " + respFormat); + LOGGER.finest("responseFormat: " + respFormat); if(respFormat.startsWith("application/fits")) { @@ -299,7 +301,7 @@ public class ServletCutout extends HttpServlet } catch(MultiValuedParamNotSupported ex) { - LOGGER.info("MultiValuedParamNotSupported: " + ex.getMessage()); + LOGGER.warning("MultiValuedParamNotSupported: " + ex.getMessage()); response.setStatus(HttpServletResponse.SC_BAD_REQUEST); response.setContentType("text/plain"); @@ -311,7 +313,7 @@ public class ServletCutout extends HttpServlet } catch(IllegalArgumentException ex) { - LOGGER.info("IllegalArgumentException: " + ex.getMessage()); + LOGGER.warning("IllegalArgumentException: " + ex.getMessage()); response.setStatus(HttpServletResponse.SC_BAD_REQUEST); response.setContentType("text/plain"); @@ -323,7 +325,7 @@ public class ServletCutout extends HttpServlet } catch(Exception ex) { - LOGGER.info("Exception: " + ex.getMessage()); + LOGGER.severe("Exception: " + ex.getMessage()); ex.printStackTrace(); response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); @@ -339,17 +341,17 @@ public class ServletCutout extends HttpServlet respOutputStream.close(); } - LOGGER.info("RUNTIME[nsec] Servlet::execRequest: "+String.valueOf(System.nanoTime() - startTime_nsec)); + LOGGER.fine("RUNTIME[sec]: "+String.valueOf( (System.nanoTime() - startTime_nsec) / 1000000000.0 )); } private String convertLocalPathnameToRemoteUrl(String localPathname, String FITScutpath, String FITSRemoteUrlCutouts) { - LOGGER.info("trace " + localPathname); + LOGGER.fine("trace " + localPathname); String fileName = localPathname.replaceAll(FITScutpath + "/", ""); - LOGGER.info("local filename: " + fileName); + LOGGER.finest("local filename: " + fileName); String remotefname = FITSRemoteUrlCutouts + "/" + fileName; - LOGGER.info("remote url : " + remotefname); + LOGGER.finest("remote url : " + remotefname); return remotefname; } diff --git a/data-access/servlet/src/main/java/webapi/UWSMCutoutWork.java b/data-access/servlet/src/main/java/webapi/UWSMCutoutWork.java index 3d59890..df5e0e1 100644 --- a/data-access/servlet/src/main/java/webapi/UWSMCutoutWork.java +++ b/data-access/servlet/src/main/java/webapi/UWSMCutoutWork.java @@ -124,11 +124,11 @@ public class UWSMCutoutWork extends JobThread private String convertLocalPathnameToRemoteUrl(String localPathname, String FITScutpath, String FITSRemoteUrlCutouts) { - //LOGGER.info("trace " + localPathname); + //LOGGER.fine("trace " + localPathname); String fileName = localPathname.replaceAll(FITScutpath + "/", ""); - //LOGGER.info("local filename: " + fileName); + //LOGGER.finer("local filename: " + fileName); String remotefname = FITSRemoteUrlCutouts + "/" + fileName; - //LOGGER.info("remote url : " + remotefname); + //LOGGER.finer("remote url : " + remotefname); return remotefname; } diff --git a/data-access/servlet/src/main/java/webapi/UWSMergeWork.java b/data-access/servlet/src/main/java/webapi/UWSMergeWork.java index 7d62fd8..230ddf3 100644 --- a/data-access/servlet/src/main/java/webapi/UWSMergeWork.java +++ b/data-access/servlet/src/main/java/webapi/UWSMergeWork.java @@ -147,11 +147,11 @@ public class UWSMergeWork extends JobThread private String convertLocalPathnameToRemoteUrl(String localPathname, String FITScutpath, String FITSRemoteUrlCutouts) { - //LOGGER.info("trace " + localPathname); + //LOGGER.fine("trace " + localPathname); String fileName = localPathname.replaceAll(FITScutpath + "/", ""); - //LOGGER.info("local filename: " + fileName); + //LOGGER.finer("local filename: " + fileName); String remotefname = FITSRemoteUrlCutouts + "/" + fileName; - //LOGGER.info("remote url : " + remotefname); + //LOGGER.finer("remote url : " + remotefname); return remotefname; } diff --git a/data-access/servlet/src/main/java/webapi/output/XmlSerializer.java b/data-access/servlet/src/main/java/webapi/output/XmlSerializer.java index cc933cd..61f96b7 100644 --- a/data-access/servlet/src/main/java/webapi/output/XmlSerializer.java +++ b/data-access/servlet/src/main/java/webapi/output/XmlSerializer.java @@ -6,7 +6,7 @@ import vo.parameter.*; public final class XmlSerializer { - private static final Logger LOGGER = Logger.getLogger("XmlSerializer"); + private static final Logger LOGGER = Logger.getLogger(XmlSerializer.class.getName()); private XmlSerializer() {} // disables instatiation @@ -15,7 +15,7 @@ public final class XmlSerializer String id, Pos pos, Band band, Time time, Pol pol, String pixels, boolean countNullValues, boolean showDuration, long startTime_msec) { - LOGGER.info("trace serialize for accessUrl: " + ((accessUrl==null)? "null":accessUrl)); + LOGGER.fine("trace serialize for accessUrl: " + ((accessUrl==null)? "null":accessUrl)); writer.println("<?xml version=\"1.0\" encoding=\"" + charEncoding + "\" standalone=\"yes\"?>"); writer.println("<results>"); @@ -55,7 +55,7 @@ public final class XmlSerializer //String id, Pos pos, Band band, Time time, Pol pol, String pixels, boolean countNullValues, boolean showDuration, long startTime_msec) { - LOGGER.info("trace serialize for accessUrl: " + ((accessUrl==null)? "null":accessUrl)); + LOGGER.fine("trace serialize for accessUrl: " + ((accessUrl==null)? "null":accessUrl)); writer.println("<?xml version=\"1.0\" encoding=\"" + charEncoding + "\" standalone=\"yes\"?>"); writer.println("<results>"); diff --git a/java-libs/lib/vlkb-volib-0.9.1-SNAPSHOT.jar b/java-libs/lib/vlkb-volib-0.9.1-SNAPSHOT.jar index f1a6a61c90acada94ec801155a5adc9f30d1b1cd..4af8f63066eaec4a80adaabf4e4dd13fb30d47c3 100644 GIT binary patch delta 9422 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 b4$c>0Y?+*qFT)g<0Tx)4FUQ7}2{HfxQy*rw delta 9468 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 U@@1H$GQffl@>ST5Wq`~802v9UOaK4? -- GitLab